code:
// Type definitions for commander
// Original definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>

// Using method rather than property for method-signature-style, to document method overloads separately. Allow either.
/* eslint-disable @typescript-eslint/method-signature-style */
/* eslint-disable @typescript-eslint/no-explicit-any */

export class CommanderError extends Error {
  code: string;
  exitCode: number;
  message: string;
  nestedError?: string;

  /**
   * Constructs the CommanderError class
   * @param exitCode - suggested exit code which could be used with process.exit
   * @param code - an id string representing the error
   * @param message - human-readable description of the error
   * @constructor
   */
  constructor(exitCode: number, code: string, message: string);
}

export class InvalidArgumentError extends CommanderError {
  /**
   * Constructs the InvalidArgumentError class
   * @param message - explanation of why argument is invalid
   * @constructor
   */
  constructor(message: string);
}
export { InvalidArgumentError as InvalidOptionArgumentError }; // deprecated old name

export class Argument {
  description: string;
  required: boolean;
  variadic: boolean;

  /**
   * Initialize a new command argument with the given name and description.
   * The default is that the argument is required, and you can explicitly
   * indicate this with <> around the name. Put [] around the name for an optional argument.
   */
  constructor(arg: string, description?: string);

  /**
   * Return argument name.
   */
  name(): string;

  /**
   * Set the default value, and optionally supply the description to be displayed in the help.
   */
  default(value: unknown, description?: string): this;

  /**
   * Set the custom handler for processing CLI command arguments into argument values.
   */
  argParser<T>(fn: (value: string, previous: T) => T): this;

  /**
   * Only allow argument value to be one of choices.
   */
  choices(values: string[]): this;

  /**
   * Make option-argument required.
   */
  argRequired(): this;

  /**
   * Make option-argument optional.
   */
  argOptional(): this;
  }

export class Option {
  flags: string;
  description: string;

  required: boolean; // A value must be supplied when the option is specified.
  optional: boolean; // A value is optional when the option is specified.
  variadic: boolean;
  mandatory: boolean; // The option must have a value after parsing, which usually means it must be specified on command line.
  optionFlags: string;
  short?: string;
  long?: string;
  negate: boolean;
  defaultValue?: any;
  defaultValueDescription?: string;
  parseArg?: <T>(value: string, previous: T) => T;
  hidden: boolean;
  argChoices?: string[];

  constructor(flags: string, description?: string);

  /**
   * Set the default value, and optionally supply the description to be displayed in the help.
   */
  default(value: unknown, description?: string): this;

  /**
   * Set environment variable to check for option value.
   * Priority order of option values is default < env < cli
   */
  env(name: string): this;

  /**
   * Calculate the full description, including defaultValue etc.
   */
  fullDescription(): string;

  /**
   * Set the custom handler for processing CLI option arguments into option values.
   */
  argParser<T>(fn: (value: string, previous: T) => T): this;

  /**
   * Whether the option is mandatory and must have a value after parsing.
   */
  makeOptionMandatory(mandatory?: boolean): this;

  /**
   * Hide option in help.
   */
  hideHelp(hide?: boolean): this;

  /**
   * Only allow option value to be one of choices.
   */
  choices(values: string[]): this;

  /**
   * Return option name.
   */
  name(): string;

  /**
   * Return option name, in a camelcase format that can be used
   * as a object attribute key.
   */
  attributeName(): string;
}

export class Help {
  /** output helpWidth, long lines are wrapped to fit */
  helpWidth?: number;
  sortSubcommands: boolean;
  sortOptions: boolean;

  constructor();

  /** Get the command term to show in the list of subcommands. */
  subcommandTerm(cmd: Command): string;
  /** Get the command description to show in the list of subcommands. */
  subcommandDescription(cmd: Command): string;
  /** Get the option term to show in the list of options. */
  optionTerm(option: Option): string;
  /** Get the option description to show in the list of options. */
  optionDescription(option: Option): string;
  /** Get the argument term to show in the list of arguments. */
  argumentTerm(argument: Argument): string;
  /** Get the argument description to show in the list of arguments. */
  argumentDescription(argument: Argument): string;

  /** Get the command usage to be displayed at the top of the built-in help. */
  commandUsage(cmd: Command): string;
  /** Get the description for the command. */
  commandDescription(cmd: Command): string;

  /** Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one. */
  visibleCommands(cmd: Command): Command[];
  /** Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one. */
  visibleOptions(cmd: Command): Option[];
  /** Get an array of the arguments which have descriptions. */
  visibleArguments(cmd: Command): Argument[];

  /** Get the longest command term length. */
  longestSubcommandTermLength(cmd: Command, helper: Help): number;
  /** Get the longest option term length. */
  longestOptionTermLength(cmd: Command, helper: Help): number;
  /** Get the longest argument term length. */
  longestArgumentTermLength(cmd: Command, helper: Help): number;
  /** Calculate the pad width from the maximum term length. */
  padWidth(cmd: Command, helper: Help): number;

  /**
   * Wrap the given string to width characters per line, with lines after the first indented.
   * Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
   */
  wrap(str: string, width: number, indent: number, minColumnWidth?: number): string;

  /** Generate the built-in help text. */
  formatHelp(cmd: Command, helper: Help): string;
}
export type HelpConfiguration = Partial<Help>;

export interface ParseOptions {
  from: 'node' | 'electron' | 'user';
}
export interface HelpContext { // optional parameter for .help() and .outputHelp()
  error: boolean;
}
export interface AddHelpTextContext { // passed to text function used with .addHelpText()
  error: boolean;
  command: Command;
}
export interface OutputConfiguration {
  writeOut?(str: string): void;
  writeErr?(str: string): void;
  getOutHelpWidth?(): number;
  getErrHelpWidth?(): number;
  outputError?(str: string, write: (str: string) => void): void;

}

export type AddHelpTextPosition = 'beforeAll' | 'before' | 'after' | 'afterAll';
export type HookEvent = 'preAction' | 'postAction';
export type OptionValueSource = 'default' | 'env' | 'config' | 'cli';

export interface OptionValues {
  [key: string]: any;
}

export class Command {
  args: string[];
  processedArgs: any[];
  commands: Command[];
  parent: Command | null;

  constructor(name?: string);

  /**
   * Set the program version to `str`.
   *
   * This method auto-registers the "-V, --version" flag
   * which will print the version number when passed.
   *
   * You can optionally supply the  flags and description to override the defaults.
   */
  version(str: string, flags?: string, description?: string): this;

  /**
   * Define a command, implemented using an action handler.
   *
   * @remarks
   * The command description is supplied using `.description`, not as a parameter to `.command`.
   *
   * @example
   * ```ts
   * program
   *   .command('clone <source> [destination]')
   *   .description('clone a repository into a newly created directory')
   *   .action((source, destination) => {
   *     console.log('clone command called');
   *   });
   * ```
   *
   * @param nameAndArgs - command name and arguments, args are  `<required>` or `[optional]` and last may also be `variadic...`
   * @param opts - configuration options
   * @returns new command
   */
  command(nameAndArgs: string, opts?: CommandOptions): ReturnType<this['createCommand']>;
  /**
   * Define a command, implemented in a separate executable file.
   *
   * @remarks
   * The command description is supplied as the second parameter to `.command`.
   *
   * @example
   * ```ts
   *  program
   *    .command('start <service>', 'start named service')
   *    .command('stop [service]', 'stop named service, or all if no name supplied');
   * ```
   *
   * @param nameAndArgs - command name and arguments, args are  `<required>` or `[optional]` and last may also be `variadic...`
   * @param description - description of executable command
   * @param opts - configuration options
   * @returns `this` command for chaining
   */
  command(nameAndArgs: string, description: string, opts?: ExecutableCommandOptions): this;

  /**
   * Factory routine to create a new unattached command.
   *
   * See .command() for creating an attached subcommand, which uses this routine to
   * create the command. You can override createCommand to customise subcommands.
   */
  createCommand(name?: string): Command;

  /**
   * Add a prepared subcommand.
   *
   * See .command() for creating an attached subcommand which inherits settings from its parent.
   *
   * @returns `this` command for chaining
   */
  addCommand(cmd: Command, opts?: CommandOptions): this;

  /**
   * Factory routine to create a new unattached argument.
   *
   * See .argument() for creating an attached argument, which uses this routine to
   * create the argument. You can override createArgument to return a custom argument.
   */
  createArgument(name: string, description?: string): Argument;

  /**
   * Define argument syntax for command.
   *
   * The default is that the argument is required, and you can explicitly
   * indicate this with <> around the name. Put [] around the name for an optional argument.
   *
   * @example
   * ```
   * program.argument('<input-file>');
   * program.argument('[output-file]');
   * ```
   *
   * @returns `this` command for chaining
   */
    argument<T>(flags: string, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): this;
    argument(name: string, description?: string, defaultValue?: unknown): this;

  /**
   * Define argument syntax for command, adding a prepared argument.
   *
   * @returns `this` command for chaining
   */
  addArgument(arg: Argument): this;

  /**
   * Define argument syntax for command, adding multiple at once (without descriptions).
   *
   * See also .argument().
   *
   * @example
   * ```
   * program.arguments('<cmd> [env]');
   * ```
   *
   * @returns `this` command for chaining
   */
  arguments(names: string): this;

  /**
   * Override default decision whether to add implicit help command.
   *
   * @example
   * ```
   * addHelpCommand() // force on
   * addHelpCommand(false); // force off
   * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details
   * ```
   *
   * @returns `this` command for chaining
   */
  addHelpCommand(enableOrNameAndArgs?: string | boolean, description?: string): this;

  /**
   * Add hook for life cycle event.
   */
  hook(event: HookEvent, listener: (thisCommand: Command, actionCommand: Command) => void | Promise<void>): this;

  /**
   * Register callback to use as replacement for calling process.exit.
   */
  exitOverride(callback?: (err: CommanderError) => never|void): this;

  /**
   * You can customise the help with a subclass of Help by overriding createHelp,
   * or by overriding Help properties using configureHelp().
   */
  createHelp(): Help;

  /**
   * You can customise the help by overriding Help properties using configureHelp(),
   * or with a subclass of Help by overriding createHelp().
   */
  configureHelp(configuration: HelpConfiguration): this;
  /** Get configuration */
  configureHelp(): HelpConfiguration;

  /**
   * The default output goes to stdout and stderr. You can customise this for special
   * applications. You can also customise the display of errors by overriding outputError.
   *
   * The configuration properties are all functions:
   * ```
   * // functions to change where being written, stdout and stderr
   * writeOut(str)
   * writeErr(str)
   * // matching functions to specify width for wrapping help
   * getOutHelpWidth()
   * getErrHelpWidth()
   * // functions based on what is being written out
   * outputError(str, write) // used for displaying errors, and not used for displaying help
   * ```
   */
  configureOutput(configuration: OutputConfiguration): this;
  /** Get configuration */
  configureOutput(): OutputConfiguration;

  /**
   * Copy settings that are useful to have in common across root command and subcommands.
   *
   * (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
   */
  copyInheritedSettings(sourceCommand: Command): this;

  /**
   * Display the help or a custom message after an error occurs.
   */
  showHelpAfterError(displayHelp?: boolean | string): this;

  /**
   * Display suggestion of similar commands for unknown commands, or options for unknown options.
   */
  showSuggestionAfterError(displaySuggestion?: boolean): this;

   /**
   * Register callback `fn` for the command.
   *
   * @example
   * ```
   * program
   *   .command('serve')
   *   .description('start service')
   *   .action(function() {
   *     // do work here
   *   });
   * ```
   *
   * @returns `this` command for chaining
   */
  action(fn: (...args: any[]) => void | Promise<void>): this;

  /**
   * Define option with `flags`, `description` and optional
   * coercion `fn`.
   *
   * The `flags` string contains the short and/or long flags,
   * separated by comma, a pipe or space. The following are all valid
   * all will output this way when `--help` is used.
   *
   *     "-p, --pepper"
   *     "-p|--pepper"
   *     "-p --pepper"
   *
   * @example
   * ```
   * // simple boolean defaulting to false
   *  program.option('-p, --pepper', 'add pepper');
   *
   *  --pepper
   *  program.pepper
   *  // => Boolean
   *
   *  // simple boolean defaulting to true
   *  program.option('-C, --no-cheese', 'remove cheese');
   *
   *  program.cheese
   *  // => true
   *
   *  --no-cheese
   *  program.cheese
   *  // => false
   *
   *  // required argument
   *  program.option('-C, --chdir <path>', 'change the working directory');
   *
   *  --chdir /tmp
   *  program.chdir
   *  // => "/tmp"
   *
   *  // optional argument
   *  program.option('-c, --cheese [type]', 'add cheese [marble]');
   * ```
   *
   * @returns `this` command for chaining
   */
  option(flags: string, description?: string, defaultValue?: string | boolean): this;
  option<T>(flags: string, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): this;
  /** @deprecated since v7, instead use choices or a custom function */
  option(flags: string, description: string, regexp: RegExp, defaultValue?: string | boolean): this;

  /**
   * Define a required option, which must have a value after parsing. This usually means
   * the option must be specified on the command line. (Otherwise the same as .option().)
   *
   * The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.
   */
  requiredOption(flags: string, description?: string, defaultValue?: string | boolean): this;
  requiredOption<T>(flags: string, description: string, fn: (value: string, previous: T) => T, defaultValue?: T): this;
  /** @deprecated since v7, instead use choices or a custom function */
  requiredOption(flags: string, description: string, regexp: RegExp, defaultValue?: string | boolean): this;

  /**
   * Factory routine to create a new unattached option.
   *
   * See .option() for creating an attached option, which uses this routine to
   * create the option. You can override createOption to return a custom option.
   */

  createOption(flags: string, description?: string): Option;

  /**
   * Add a prepared Option.
   *
   * See .option() and .requiredOption() for creating and attaching an option in a single call.
   */
  addOption(option: Option): this;

  /**
   * Whether to store option values as properties on command object,
   * or store separately (specify false). In both cases the option values can be accessed using .opts().
   *
   * @returns `this` command for chaining
   */
  storeOptionsAsProperties<T extends OptionValues>(): this & T;
  storeOptionsAsProperties<T extends OptionValues>(storeAsProperties: true): this & T;
  storeOptionsAsProperties(storeAsProperties?: boolean): this;

  /**
   * Retrieve option value.
   */
  getOptionValue(key: string): any;

  /**
   * Store option value.
   */
  setOptionValue(key: string, value: unknown): this;

  /**
   * Store option value and where the value came from.
   */
  setOptionValueWithSource(key: string, value: unknown, source: OptionValueSource): this;

  /**
   * Retrieve option value source.
   */
  getOptionValueSource(key: string): OptionValueSource;

   /**
   * Alter parsing of short flags with optional values.
   *
   * @example
   * ```
   * // for `.option('-f,--flag [value]'):
   * .combineFlagAndOptionalValue(true)  // `-f80` is treated like `--flag=80`, this is the default behaviour
   * .combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`
   * ```
   *
   * @returns `this` command for chaining
   */
  combineFlagAndOptionalValue(combine?: boolean): this;

  /**
   * Allow unknown options on the command line.
   *
   * @returns `this` command for chaining
   */
  allowUnknownOption(allowUnknown?: boolean): this;

  /**
   * Allow excess command-arguments on the command line. Pass false to make excess arguments an error.
   *
   * @returns `this` command for chaining
   */
  allowExcessArguments(allowExcess?: boolean): this;

  /**
   * Enable positional options. Positional means global options are specified before subcommands which lets
   * subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.
   *
   * The default behaviour is non-positional and global options may appear anywhere on the command line.
   *
   * @returns `this` command for chaining
   */
  enablePositionalOptions(positional?: boolean): this;

  /**
   * Pass through options that come after command-arguments rather than treat them as command-options,
   * so actual command-options come before command-arguments. Turning this on for a subcommand requires
   * positional options to have been enabled on the program (parent commands).
   *
   * The default behaviour is non-positional and options may appear before or after command-arguments.
   *
   * @returns `this` command for chaining
   */
  passThroughOptions(passThrough?: boolean): this;

  /**
   * Parse `argv`, setting options and invoking commands when defined.
   *
   * The default expectation is that the arguments are from node and have the application as argv[0]
   * and the script being run in argv[1], with user parameters after that.
   *
   * @example
   * ```
   * program.parse(process.argv);
   * program.parse(); // implicitly use process.argv and auto-detect node vs electron conventions
   * program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
   * ```
   *
   * @returns `this` command for chaining
   */
  parse(argv?: string[], options?: ParseOptions): this;

  /**
   * Parse `argv`, setting options and invoking commands when defined.
   *
   * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.
   *
   * The default expectation is that the arguments are from node and have the application as argv[0]
   * and the script being run in argv[1], with user parameters after that.
   *
   * @example
   * ```
   * program.parseAsync(process.argv);
   * program.parseAsync(); // implicitly use process.argv and auto-detect node vs electron conventions
   * program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]
   * ```
   *
   * @returns Promise
   */
  parseAsync(argv?: string[], options?: ParseOptions): Promise<this>;

  /**
   * Parse options from `argv` removing known options,
   * and return argv split into operands and unknown arguments.
   *
   *     argv => operands, unknown
   *     --known kkk op => [op], []
   *     op --known kkk => [op], []
   *     sub --unknown uuu op => [sub], [--unknown uuu op]
   *     sub -- --unknown uuu op => [sub --unknown uuu op], []
   */
  parseOptions(argv: string[]): ParseOptionsResult;

  /**
   * Return an object containing options as key-value pairs
   */
  opts<T extends OptionValues>(): T;

  /**
   * Set the description.
   *
   * @returns `this` command for chaining
   */

  description(str: string): this;
  /** @deprecated since v8, instead use .argument to add command argument with description */
  description(str: string, argsDescription: {[argName: string]: string}): this;
  /**
   * Get the description.
   */
  description(): string;

  /**
   * Set an alias for the command.
   *
   * You may call more than once to add multiple aliases. Only the first alias is shown in the auto-generated help.
   *
   * @returns `this` command for chaining
   */
  alias(alias: string): this;
  /**
   * Get alias for the command.
   */
  alias(): string;

  /**
   * Set aliases for the command.
   *
   * Only the first alias is shown in the auto-generated help.
   *
   * @returns `this` command for chaining
   */
  aliases(aliases: string[]): this;
  /**
   * Get aliases for the command.
   */
  aliases(): string[];

  /**
   * Set the command usage.
   *
   * @returns `this` command for chaining
   */
  usage(str: string): this;
  /**
   * Get the command usage.
   */
  usage(): string;

  /**
   * Set the name of the command.
   *
   * @returns `this` command for chaining
   */
  name(str: string): this;
  /**
   * Get the name of the command.
   */
  name(): string;

  /**
   * Output help information for this command.
   *
   * Outputs built-in help, and custom text added using `.addHelpText()`.
   *
   */
  outputHelp(context?: HelpContext): void;
  /** @deprecated since v7 */
  outputHelp(cb?: (str: string) => string): void;

  /**
   * Return command help documentation.
   */
  helpInformation(context?: HelpContext): string;

  /**
   * You can pass in flags and a description to override the help
   * flags and help description for your command. Pass in false
   * to disable the built-in help option.
   */
  helpOption(flags?: string | boolean, description?: string): this;

  /**
   * Output help information and exit.
   *
   * Outputs built-in help, and custom text added using `.addHelpText()`.
   */
  help(context?: HelpContext): never;
  /** @deprecated since v7 */
  help(cb?: (str: string) => string): never;

  /**
   * Add additional text to be displayed with the built-in help.
   *
   * Position is 'before' or 'after' to affect just this command,
   * and 'beforeAll' or 'afterAll' to affect this command and all its subcommands.
   */
  addHelpText(position: AddHelpTextPosition, text: string): this;
  addHelpText(position: AddHelpTextPosition, text: (context: AddHelpTextContext) => string): this;

  /**
   * Add a listener (callback) for when events occur. (Implemented using EventEmitter.)
   */
  on(event: string | symbol, listener: (...args: any[]) => void): this;
}

export interface CommandOptions {
  hidden?: boolean;
  isDefault?: boolean;
  /** @deprecated since v7, replaced by hidden */
  noHelp?: boolean;
}
export interface ExecutableCommandOptions extends CommandOptions {
  executableFile?: string;
}

export interface ParseOptionsResult {
  operands: string[];
  unknown: string[];
}

export function createCommand(name?: string): Command;
export function createOption(flags: string, description?: string): Option;
export function createArgument(name: string, description?: string): Argument;

export const program: Command;


code:
var commondir = require('../');
var dir = commondir(process.argv.slice(2));
console.log(dir);

license: mit


code:
var path = require('path');

module.exports = function (basedir, relfiles) {
    if (relfiles) {
        var files = relfiles.map(function (r) {
            return path.resolve(basedir, r);
        });
    }
    else {
        var files = basedir;
    }

    var res = files.slice(1).reduce(function (ps, file) {
        if (!file.match(/^([A-Za-z]:)?\/|\\/)) {
            throw new Error('relative path without a basedir');
        }

        var xs = file.split(/\/+|\\+/);
        for (
            var i = 0;
            ps[i] === xs[i] && i < Math.min(ps.length, xs.length);
            i++
        );
        return ps.slice(0, i);
    }, files[0].split(/\/+|\\+/));

    // Windows correctly handles paths with forward-slashes
    return res.length > 1 ? res.join('/') : '/'
};


commondir

description: compute the closest common parent for file paths

test: tape test/*.js

type: git

keywords: common path directory file parent root

license: MIT


code:
# commondir

compute the closest common parent directory among an array of directories

# example

``` js
var commondir = require('commondir');
var dir = commondir(process.argv.slice(2))
console.log(dir);
```

output:

```
$ node dir.js /x/y/z /x/y /x/y/w/q
/x/y
$ node ../baz ../../foo/quux ./bizzy
/foo
```

# methods

``` js
var commondir = require('commondir');
```

## commondir(absolutePaths)

Compute the closest common parent directory for an array `absolutePaths`.

## commondir(basedir, relativePaths)

Compute the closest common parent directory for an array `relativePaths` which
will be resolved for each `dir` in `relativePaths` according to:
`path.resolve(basedir, dir)`.

# install

With [npm](https://npmjs.org) do:

```
npm install commondir
```

# license

MIT


code:
var test = require('tape');
var commondir = require('../');

test('common', function (t) {
    t.equal(
        commondir([ '/foo', '//foo/bar', '/foo//bar/baz' ]),
        '/foo'
    );
    t.equal(
        commondir([ '/a/b/c', '/a/b', '/a/b/c/d/e' ]),
        '/a/b'
    );
    t.equal(
        commondir([ '/x/y/z/w', '/xy/z', '/x/y/z' ]),
        '/'
    );
    t.equal(
        commondir([ 'X:\\foo', 'X:\\\\foo\\bar', 'X://foo/bar/baz' ]),
        'X:/foo'
    );
    t.equal(
        commondir([ 'X:\\a\\b\\c', 'X:\\a\\b', 'X:\\a\\b\\c\\d\\e' ]),
        'X:/a/b'
    );
    t.equal(
        commondir([ 'X:\\x\\y\\z\\w', '\\\\xy\\z', '\\x\\y\\z' ]),
        '/'
    );
    t.throws(function () {
        commondir([ '/x/y/z/w', 'qrs', '/x/y/z' ]);
    });
    t.end();
});

test('base', function (t) {
    t.equal(
        commondir('/foo/bar', [ 'baz', './quux', '../bar/bazzy' ]),
        '/foo/bar'
    );
    t.equal(
        commondir('/a/b', [ 'c', '../b/.', '../../a/b/e' ]),
        '/a/b'
    );
    t.equal(
        commondir('/a/b/c', [ '..', '../d', '../../a/z/e' ]),
        '/a'
    );
    t.equal(
        commondir('/foo/bar', [ 'baz', '.\\quux', '..\\bar\\bazzy' ]),
        '/foo/bar'
    );
    // Tests including X:\ basedirs must wait until path.resolve supports
    // Windows-style paths, starting in Node.js v0.5.X
    t.end();
});


code:
# compressible

[![NPM Version][npm-version-image]][npm-url]
[![NPM Downloads][npm-downloads-image]][npm-url]
[![Node.js Version][node-version-image]][node-version-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]

Compressible `Content-Type` / `mime` checking.

## Installation

```sh
$ npm install compressible
```

## API

<!-- eslint-disable no-unused-vars -->

```js
var compressible = require('compressible')
```

### compressible(type)

Checks if the given `Content-Type` is compressible. The `type` argument is expected
to be a value MIME type or `Content-Type` string, though no validation is performed.

The MIME is looked up in the [`mime-db`](https://www.npmjs.com/package/mime-db) and
if there is compressible information in the database entry, that is returned. Otherwise,
this module will fallback to `true` for the following types:

  * `text/*`
  * `*/*+json`
  * `*/*+text`
  * `*/*+xml`

If this module is not sure if a type is specifically compressible or specifically
uncompressible, `undefined` is returned.

<!-- eslint-disable no-undef -->

```js
compressible('text/html') // => true
compressible('image/png') // => false
```

## License

[MIT](LICENSE)

[coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/compressible/master
[coveralls-url]: https://coveralls.io/r/jshttp/compressible?branch=master
[node-version-image]: https://badgen.net/npm/node/compressible
[node-version-url]: https://nodejs.org/en/download
[npm-downloads-image]: https://badgen.net/npm/dm/compressible
[npm-url]: https://npmjs.org/package/compressible
[npm-version-image]: https://badgen.net/npm/v/compressible
[travis-image]: https://badgen.net/travis/jshttp/compressible/master
[travis-url]: https://travis-ci.org/jshttp/compressible


code:
/*!
 * compressible
 * Copyright(c) 2013 Jonathan Ong
 * Copyright(c) 2014 Jeremiah Senkpiel
 * Copyright(c) 2015 Douglas Christopher Wilson
 * MIT Licensed
 */

'use strict'

/**
 * Module dependencies.
 * @private
 */

var db = require('mime-db')

/**
 * Module variables.
 * @private
 */

var COMPRESSIBLE_TYPE_REGEXP = /^text\/|\+(?:json|text|xml)$/i
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/

/**
 * Module exports.
 * @public
 */

module.exports = compressible

/**
 * Checks if a type is compressible.
 *
 * @param {string} type
 * @return {Boolean} compressible
 * @public
 */

function compressible (type) {
  if (!type || typeof type !== 'string') {
    return false
  }

  // strip parameters
  var match = EXTRACT_TYPE_REGEXP.exec(type)
  var mime = match && match[1].toLowerCase()
  var data = db[mime]

  // return database information
  if (data && data.compressible !== undefined) {
    return data.compressible
  }

  // fallback to regexp or unknown
  return COMPRESSIBLE_TYPE_REGEXP.test(mime) || undefined
}


compressible

description: Compressible Content-Type / mime checking

contributors: Douglas Christopher Wilson <doug@somethingdoug.com>

contributors: Jonathan Ong <me@jongleberry.com> (http://jongleberry.com)

contributors: Jeremiah Senkpiel <fishrock123@rocketmail.com> (https://searchbeam.jit.su)

repository: jshttp/compressible

keywords: compress gzip mime content-type

lint: eslint --plugin markdown --ext js,md .

test: mocha --reporter spec --bail --check-leaks test/

test-cov: nyc --reporter=html --reporter=text npm test

test-travis: nyc --reporter=text npm test

version: node scripts/version-history.js && git add HISTORY.md


code:
# compressing

[![NPM version][npm-image]][npm-url]
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]

[npm-image]: https://img.shields.io/npm/v/compressing.svg?style=flat-square
[npm-url]: https://npmjs.org/package/compressing
[codecov-image]: https://codecov.io/gh/node-modules/compressing/branch/master/graph/badge.svg
[codecov-url]: https://codecov.io/gh/node-modules/compressing
[download-image]: https://img.shields.io/npm/dm/compressing.svg?style=flat-square
[download-url]: https://npmjs.org/package/compressing

The missing compressing and uncompressing lib for node.

Currently supported:

- tar
- gzip
- tgz
- zip

## Install

```bash
npm install compressing
```

## Usage

### Compress a single file

Use gzip as an example, tar, tgz and zip is same as gzip.

__promise style__

```js
const compressing = require('compressing');

// compress a file
compressing.gzip.compressFile('file/path/to/compress', 'path/to/destination.gz')
.then(compressDone)
.catch(handleError);

// compress a file buffer
compressing.gzip.compressFile(buffer, 'path/to/destination.gz')
.then(compressDone)
.catch(handleError);

// compress a stream
compressing.gzip.compressFile(stream, 'path/to/destination.gz')
.then(compressDone)
.catch(handleError);
```

__stream style__

```js
const compressing = require('compressing');

new compressing.gzip.FileStream({ source: 'file/path/to/compress' })
  .on('error', handleError)
  .pipe(fs.createWriteStream('path/to/destination.gz'))
  .on('error', handleError);

// It's a transform stream, so you can pipe to it
fs.createReadStream('file/path/to/compress')
  .on('error', handleError)
  .pipe(new compressing.gzip.FileStream())
  .on('error', handleError)
  .pipe(fs.createWriteStream('path/to/destination.gz'))
  .on('error', handleError);

// You should take care of stream errors in caution, use pump to handle error in one place
const pump = require('pump');
const sourceStream = fs.createReadStream('file/path/to/compress');
const gzipStream = new compressing.gzip.FileStream();
const destStream = fs.createWriteStream('path/to/destination.gz');
pump(sourceStream, gzipStream, destStream, handleError);
```

### Compress a dir

Use tar as an example, tgz and zip is same as gzip.

__Gzip only support compressing a single file. if you want to compress a dir with gzip, then you may need tgz instead.__

__promise style__

```js
const compressing = require('compressing');
compressing.tar.compressDir('dir/path/to/compress', 'path/to/destination.tar')
.then(compressDone)
.catch(handleError);
```

__stream style__

```js
const compressing = require('compressing');

const tarStream = new compressing.tar.Stream();
tarStream.addEntry('dir/path/to/compress');

tarStream
  .on('error', handleError)
  .pipe(fs.createWriteStream('path/to/destination.tar'))
  .on('error', handleError);

// You should take care of stream errors in caution, use pump to handle error in one place
const tarStream = new compressing.tar.Stream();
tarStream.addEntry('dir/path/to/compress');
const destStream = fs.createWriteStream('path/to/destination.tar');
pump(tarStream, destStream, handleError);
```

Stream is very powerful, you can compress multiple entries in it;

```js
const tarStream = new compressing.tar.Stream();
// dir
tarStream.addEntry('dir/path/to/compress');

// file
tarStream.addEntry('file/path/to/compress');

// buffer
tarStream.addEntry(buffer);

// stream
tarStream.addEntry(stream);

const destStream = fs.createWriteStream('path/to/destination.tar');
pipe(tarStream, destStream, handleError);
```

### Uncompress a file

__promise style__

```js
const compressing = require('compressing');

// uncompress a file
compressing.tgz.uncompress('file/path/to/uncompress.tgz', 'path/to/destination/dir')
.then(uncompressDone)
.catch(handleError);

// uncompress a file buffer
compressing.tgz.uncompress(buffer, 'path/to/destination/dir')
.then(uncompressDone)
.catch(handleError);

// uncompress a stream
compressing.tgz.uncompress(stream, 'path/to/destination/dir')
.then(uncompressDone)
.catch(handleError);
```

__Note: tar, tgz and zip have the same uncompressing API as above: destination should be a path of a directory, while that of gzip is slightly different: destination must be a file or filestream.__

And working with urllib is super easy. Let's download a tgz file and uncompress to a directory:

```js
const urllib = require('urllib');
const targetDir = require('os').tmpdir();
const compressing = require('compressing');

urllib.request('http://registry.npmjs.org/pedding/-/pedding-1.1.0.tgz', {
  streaming: true,
  followRedirect: true,
})
.then(result => compressing.tgz.uncompress(result.res, targetDir))
.then(() => console.log('uncompress done'))
.catch(console.error);
```

__stream style__

```js
const compressing = require('compressing');
const mkdirp = require('mkdirp');

function onEntry(header, stream, next) => {
  stream.on('end', next);

  // header.type => file | directory
  // header.name => path name

  if (header.type === 'file') {
    stream.pipe(fs.createWriteStream(path.join(destDir, header.name)));
  } else { // directory
    mkdirp(path.join(destDir, header.name), err => {
      if (err) return handleError(err);
      stream.resume();
    });
  }
}

new compressing.tgz.UncompressStream({ source: 'file/path/to/uncompress.tgz' })
  .on('error', handleError)
  .on('finish', handleFinish) // uncompressing is done
  .on('entry', onEntry);

// It's a writable stream, so you can pipe to it
fs.createReadStream('file/path/to/uncompress')
  .on('error', handleError)
  .pipe(new compressing.tgz.UncompressStream())
  .on('error', handleError)
  .on('finish', handleFinish) // uncompressing is done
  .on('entry', onEntry);
```

**Note: tar, tgz and zip have the same uncompressing streaming API as above: it's a writable stream, and entries will be emitted while uncompressing one after one another, while that of gzip is slightly different: gzip.UncompressStream is a transform stream, so no `entry` event will be emitted and you can just pipe to another stream**

This constrants is brought by Gzip algorithm itself, it only support compressing one file and uncompress one file.

```js
new compressing.gzip.UncompressStream({ source: 'file/path/to/uncompress.gz' })
  .on('error', handleError)
  .pipe(fs.createWriteStream('path/to/dest/file'))
  .on('error', handleError);
```

## API

### compressFile

Use this API to compress a single file. This is a convenient method, which wraps FileStream API below, but you can handle error in one place.

- gzip.compressFile(source, dest, opts)
- tar.compressFile(source, dest, opts)
- tgz.compressFile(source, dest, opts)
- zip.compressFile(source, dest, opts)

Params

- source {String|Buffer|Stream} - source to be compressed, could be a file path, buffer, or a readable stream
- dest {String|Stream} - compressing destination, could be a file path(eg. `/path/to/xx.tgz`), or a writable stream.
- opts {Object} - usually you don't need it

Returns a promise object.

### compressDir

Use this API to compress a dir. This is a convenient method, which wraps Stream API below, but you can handle error in one place.

__Note: gzip do not have a compressDir method, you may need tgz instead.__

- tar.compressDir(source, dest, opts)
- tgz.compressDir(source, dest, opts)
- zip.compressDir(source, dest, opts)

Params

- source {String|Buffer|Stream} - source to be compressed
- dest {String|Stream} - compressing destination, could be a file path(eg. `/path/to/xx.tgz`), or a writable stream.
- opts {Object} - usually you don't need it

### uncompress

Use this API to uncompress a file. This is a convenient method, which wraps UncompressStream API below, but you can handle error in one place. RECOMMANDED.

- tar.uncompress(source, dest, opts)
- tgz.uncompress(source, dest, opts)
- zip.uncompress(source, dest, opts)
- gzip.uncompress(source, dest, opts)

Params

- source {String|Buffer|Stream} - source to be uncompressed
- dest {String|Stream} - uncompressing destination. When uncompressing tar, tgz and zip, it should be a directory path (eg. `/path/to/xx`). __When uncompressing gzip, it should be a file path or a writable stream.__
- opts {Object} - usually you don't need it
  - opts.zipFileNameEncoding {String} - Only work on zip format, default is 'utf8'.
    Major non-UTF8 encodings by languages:

    - Korean: cp949, euc-kr
    - Japanese: sjis (shift_jis), cp932, euc-jp
    - Chinese: gbk, gb18030, gb2312, cp936, hkscs, big5, cp950

### FileStream

The transform stream to compress a single file.

__Note: If you are not very familiar with streams, just use compressFile() API, error can be handled in one place.__

- new gzip.FileStream(opts)
- new tar.FileStream(opts)
- new tgz.FileStream(opts)
- new zip.FileStream(opts)

Common params:

- opts.source {String|Buffer|Stream} - source to be compressed, could be a file path, buffer, or a readable stream.

Gzip params:

- opts.zlib - {Object} gzip.FileStream uses zlib to compress, pass this param to control the behavior of zlib.

Tar params:

- opts.relativePath {String} - Adds a file from source into the compressed result file as opts.relativePath. Uncompression programs would extract the file from the compressed file as relativePath. If opts.source is a file path, opts.relativePath is optional, otherwise it's required.
- opts.size {Number} - Tar compression requires the size of file in advance. When opts.source is a stream, the size of it cannot be calculated unless load all content of the stream into memory(the default behavior, but loading all data into memory could be a very bad idea). Pass opts.size to avoid loading all data into memory, or a warning will be shown.
- opts.suppressSizeWarning {Boolean} - Pass true to suppress the size warning mentioned.

Tgz params:

tgz.FileStream is a combination of tar.FileStream and gzip.FileStream, so the params are the combination of params of tar and gzip.

Zip params:

- opts.relativePath {String} - Adds a file from source into the compressed result file as opts.relativePath. Uncompression programs would extract the file from the compressed file as relativePath. If opts.source is a file path, opts.relativePath is optional, otherwise it's required.
- opts.yazl {Object} - zip.FileStream compression uses [yazl](https://github.com/thejoshwolfe/yazl), pass this param to control the behavior of yazl.

### Stream

The readable stream to compress anything as you need.

__Note: If you are not very familiar with streams, just use compressFile() and compressDir() API, error can be handled in one place.__

__Gzip only support compressing a single file. So gzip.Stream is not available.__

__Constructor__

- new tar.Stream()
- new tgz.Stream()
- new zip.Stream()

No options in all constructors.

__Instance methods__

- addEntry(entry, opts)

Params

- entry {String|Buffer|Stream} - entry to compress, cound be a file path, a dir path, a buffer, or a stream.
- opts.relativePath {String} - uncompression programs would extract the file from the compressed file as opts.relativePath. If entry is a file path or a dir path, opts.relativePath is optional, otherwise it's required.
- opts.ignoreBase {Boolean} - when entry is a dir path, and opts.ignoreBase is set to true, the compression will contain files relative to the path passed, and not with the path included.

### UncompressStream

The writable stream to uncompress anything as you need.

__Note: If you are not very familiar with streams, just use `uncompress()` API, error can be handled in one place.__

__Gzip only support compressing and uncompressing one single file. So gzip.UncompressStream is a transform stream which is different from others.__

__Constructor__

- new gzip.UncompressStream(opts)
- new tar.UncompressStream(opts)
- new tgz.UncompressStream(opts)
- new zip.UncompressStream(opts)

Common params:

- opts.source {String|Buffer|Stream} - source to be uncompressed, could be a file path, buffer, or a readable stream.

__CAUTION for zip.UncompressStream__

Due to the design of the .zip file format, it's impossible to interpret a .zip file without loading all data into memory.

Although the API is streaming style(try to keep it handy), it still loads all data into memory.

<https://github.com/thejoshwolfe/yauzl#no-streaming-unzip-api>

## Contributors

|[
fengmk2](https://github.com/fengmk2)
|[
shaoshuai0102](https://github.com/shaoshuai0102)
|[
popomore](https://github.com/popomore)
|[
semantic-release-bot](https://github.com/semantic-release-bot)
|[
DiamondYuan](https://github.com/DiamondYuan)
|[
acyza](https://github.com/acyza)
|
| :---: | :---: | :---: | :---: | :---: | :---: |
|[
bytemain](https://github.com/bytemain)
|[
rickyes](https://github.com/rickyes)
|[
Ryqsky](https://github.com/Ryqsky)
|[
songhn233](https://github.com/songhn233)
|[
Infiltrator](https://github.com/Infiltrator)
|[
ZeekoZhu](https://github.com/ZeekoZhu)
|
[
killagu](https://github.com/killagu)
|[
okaponta](https://github.com/okaponta)
|[
ShadyZOZ](https://github.com/ShadyZOZ)

This project follows the git-contributor [spec](https://github.com/xudafeng/git-contributor), auto updated at `Thu Aug 03 2023 01:39:37 GMT+0800`.


code:
import { ReadStream, WriteStream } from 'fs'

type sourceType = string | Buffer | ReadStream

type destType = string | WriteStream

interface streamEntryOpts {
  relativePath?: string
  ignoreBase?: boolean
  size?: number
  suppressSizeWarning?: boolean
}

interface streamHeader {
  type: 'file' | 'directory',
  name: string
}

interface streamHeaderWithMode {
  type: 'file' | 'directory',
  name: string
  mode: number
}

export namespace gzip {

  function compressFile(source: sourceType, dest: destType, opts?: any): Promise<void>

  function uncompress(source: sourceType, dest: destType, opts?: any): Promise<void>

  function decompress(source: sourceType, dest: destType, opts?: any): Promise<void>

  export class FileStream extends ReadStream {

    constructor(opts?: {
      zlib?: object,
      source: sourceType
    });

  }

  export class UncompressStream extends WriteStream {

    constructor(opts?: {
      zlib?: object,
      source: sourceType
    });

    on(event: string, listener: (...args: any[]) => void): this
    on(event: 'error', listener: (err: Error) => void): this

  }

}

export namespace tar {

  function compressFile(source: sourceType, dest: destType, opts?: any): Promise<void>

  function compressDir(source: sourceType, dest: destType, opts?: any): Promise<void>

  function uncompress(source: sourceType, dest: string, opts?: any): Promise<void>

  function decompress(source: sourceType, dest: string, opts?: any): Promise<void>

  export class Stream extends ReadStream {

    constructor();

    addEntry(entry: string, opts?: streamEntryOpts): void

    addEntry(entry: Buffer | ReadStream, opts: streamEntryOpts): void
  }

  export class FileStream extends ReadStream {

    constructor(opts?: {
      relativePath?: string,
      size?: number,
      suppressSizeWarning?: boolean,
      source?: sourceType
    });

  }

  export class UncompressStream extends WriteStream {

    constructor(opts?: {
      source: sourceType
    });

    on(event: string, listener: (...args: any[]) => void): this
    on(event: 'entry', listener: (header: streamHeaderWithMode, stream: ReadStream, next: () => void) => void): this
    on(event: 'finish', listener: () => void): this
    on(event: 'error', listener: (err: Error) => void): this

  }

}

export namespace tgz {

  function compressFile(source: sourceType, dest: destType, opts?: any): Promise<void>

  function compressDir(source: sourceType, dest: destType, opts?: any): Promise<void>

  function uncompress(source: sourceType, dest: string, opts?: any): Promise<void>

  function decompress(source: sourceType, dest: string, opts?: any): Promise<void>

  export class Stream extends ReadStream {

    constructor();

    addEntry(entry: string, opts?: streamEntryOpts): void

    addEntry(entry: Buffer | ReadStream, opts: streamEntryOpts): void
  }

  export class FileStream extends ReadStream {

    constructor(opts?: {
      relativePath?: string,
      size?: number,
      suppressSizeWarning?: boolean,
      zlib?: object,
      source?: sourceType
    });

  }

  export class UncompressStream extends WriteStream {

    constructor(opts?: {
      source?: sourceType,
      strip?: number
    });

    on(event: string, listener: (...args: any[]) => void): this
    on(event: 'entry', listener: (header: streamHeaderWithMode, stream: ReadStream, next: () => void) => void): this
    on(event: 'finish', listener: () => void): this
    on(event: 'error', listener: (err: Error) => void): this

  }

}

export namespace zip {

  function compressFile(source: sourceType, dest: destType, opts?: any): Promise<void>

  function compressDir(source: sourceType, dest: destType, opts?: any): Promise<void>

  function uncompress(source: sourceType, dest: string, opts?: any): Promise<void>

  function decompress(source: sourceType, dest: string, opts?: any): Promise<void>

  export class Stream extends ReadStream {

    constructor();

    addEntry(entry: string, opts?: streamEntryOpts): void

    addEntry(entry: Buffer | ReadStream, opts: streamEntryOpts): void
  }

  export class FileStream extends ReadStream {

    /**
     *  If opts.source is a file path, opts.relativePath is optional, otherwise it's required.
     *
     *  @param opts
     */
    constructor(opts?: {
      relativePath?: string,
      yazl?: object,
      source: string
    } | {
      relativePath: string,
      yazl?: object,
      source?: Buffer | ReadStream
    });

  }

  export class UncompressStream extends WriteStream {

    constructor(opts?: {
      source?: sourceType,
      strip?: number,
      zipFileNameEncoding?: string
    });

    on(event: string, listener: (...args: any[]) => void): this
    on(event: 'entry', listener: (header: streamHeaderWithMode, stream: ReadStream, next: () => void) => void): this
    on(event: 'finish', listener: () => void): this
    on(event: 'error', listener: (err: Error) => void): this

  }

}


code:
'use strict';

exports.zip = require('./lib/zip');
exports.gzip = require('./lib/gzip');
exports.tar = require('./lib/tar');
exports.tgz = require('./lib/tgz');


code:
'use strict';

const stream = require('stream');

class BaseStream extends stream.Readable {
  addEntry(/* entry, opts */) {
    throw new Error('.addEntry not implemented in sub class!');
  }

  _read() {}

  emit(event, data) {
    if (event === 'error') {
      const error = data;
      if (error.name === 'Error') {
        error.name = this.constructor.name + 'Error';
      }
    }
    super.emit(event, data);
  }
}

module.exports = BaseStream;


code:
'use strict';

const stream = require('stream');

class UncompressBaseStream extends stream.Writable {
  emit(event, data) {
    if (event === 'error') {
      const error = data;
      if (error.name === 'Error') {
        error.name = this.constructor.name + 'Error';
      }
    }
    super.emit.apply(this, arguments);
  }
}

module.exports = UncompressBaseStream;


code:
'use strict';

const fs = require('fs');
const zlib = require('zlib');
const utils = require('../utils');
const streamifier = require('streamifier');

class GzipFileStream extends zlib.Gzip {
  constructor(opts) {
    opts = opts || {};
    super(opts.zlib);

    const sourceType = utils.sourceType(opts.source);

    if (sourceType === 'file') {
      const stream = fs.createReadStream(opts.source, opts.fs);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'buffer') {
      const stream = streamifier.createReadStream(opts.source, opts.streamifier);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'stream') {
      opts.source.on('error', err => this.emit('error', err));
      opts.source.pipe(this);
    }

    // else undefined: do nothing
  }
}

module.exports = GzipFileStream;


code:
'use strict';

const utils = require('../utils');
const GzipFileStream = require('./file_stream');
const GzipUncompressStream = require('./uncompress_stream');

exports.FileStream = GzipFileStream;
exports.UncompressStream = GzipUncompressStream;
exports.compressFile = utils.makeFileProcessFn(GzipFileStream);
exports.uncompress = utils.makeFileProcessFn(GzipUncompressStream);
exports.decompress = utils.makeFileProcessFn(GzipUncompressStream);


code:
'use strict';

const fs = require('fs');
const zlib = require('zlib');
const utils = require('../utils');
const streamifier = require('streamifier');

class GzipUncompressStream extends zlib.Unzip {
  constructor(opts) {
    opts = opts || {};
    super(opts.zlib);

    const sourceType = utils.sourceType(opts.source);

    if (sourceType === 'file') {
      const stream = fs.createReadStream(opts.source, opts.fs);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'buffer') {
      const stream = streamifier.createReadStream(opts.source, opts.streamifier);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'stream') {
      opts.source.on('error', err => this.emit('error', err));
      opts.source.pipe(this);
    }

    // else: waiting to be piped
  }
}

module.exports = GzipUncompressStream;


code:
'use strict';

const fs = require('fs');
const path = require('path');
const stream = require('stream');
const tar = require('tar-stream');
const utils = require('../utils');
const ready = require('get-ready');

class TarFileStream extends stream.Transform {
  constructor(opts) {
    super(opts);

    const pack = tar.pack();
    pack.on('data', chunk => this.push(chunk));
    pack.on('end', () => this.ready(true));

    const sourceType = utils.sourceType(opts.source);

    if (sourceType === 'file') {
      // stat file to get file size
      fs.stat(opts.source, (err, stat) => {
        if (err) return this.emit('error', err);
        this.entry = pack.entry({ name: opts.relativePath || path.basename(opts.source), size: stat.size, mode: stat.mode & 0o777 }, err => {
          if (err) return this.emit('error', err);
          pack.finalize();
        });
        const stream = fs.createReadStream(opts.source, opts.fs);
        stream.on('error', err => this.emit('error', err));
        stream.pipe(this);
      });
    } else if (sourceType === 'buffer') {
      if (!opts.relativePath) return this.emit('error', 'opts.relativePath is required if opts.source is a buffer');

      pack.entry({ name: opts.relativePath }, opts.source);
      pack.finalize();
      this.end();
    } else { // stream or undefined
      if (!opts.relativePath) return process.nextTick(() => this.emit('error', 'opts.relativePath is required'));

      if (opts.size) {
        this.entry = pack.entry({ name: opts.relativePath, size: opts.size }, err => {
          if (err) return this.emit('error', err);
          pack.finalize();
        });
      } else {
        if (!opts.suppressSizeWarning) {
          console.warn('You should specify the size of streamming data by opts.size to prevent all streaming data from loading into memory. If you are sure about memory cost, pass opts.suppressSizeWarning: true to suppress this warning');
        }
        const buf = [];
        this.entry = new stream.Writable({
          write(chunk, _, callback) {
            buf.push(chunk);
            callback();
          },
        });
        this.entry.on('finish', () => {
          pack.entry({ name: opts.relativePath }, Buffer.concat(buf));
          pack.finalize();
        });
      }

      if (sourceType === 'stream') {
        opts.source.on('error', err => this.emit('error', err));
        opts.source.pipe(this);
      }
    }
  }

  _transform(chunk, encoding, callback) {
    if (this.entry) {
      this.entry.write(chunk, encoding, callback);
    }
  }

  _flush(callback) {
    if (this.entry) {
      this.entry.end();
    }
    this.ready(callback);
  }
}

ready.mixin(TarFileStream.prototype);

module.exports = TarFileStream;


code:
'use strict';

const utils = require('../utils');
const TarStream = require('./stream');
const TarFileStream = require('./file_stream');
const TarUncompressStream = require('./uncompress_stream');

exports.Stream = TarStream;
exports.FileStream = TarFileStream;
exports.UncompressStream = TarUncompressStream;
exports.compressDir = utils.makeCompressDirFn(TarStream);
exports.compressFile = utils.makeFileProcessFn(TarFileStream);
exports.uncompress = utils.makeUncompressFn(TarUncompressStream);
exports.decompress = utils.makeUncompressFn(TarUncompressStream);


code:
'use strict';

const fs = require('fs');
const path = require('path');
const stream = require('stream');
const tar = require('tar-stream');
const utils = require('../utils');
const BaseStream = require('../base_stream');

class TarStream extends BaseStream {
  constructor(opts) {
    super(opts);

    this._waitingEntries = [];
    this._processing = false;
    this._init(opts);
  }

  _init() {
    const pack = this._pack = tar.pack();
    pack.on('end', () => this.push(null));
    pack.on('data', chunk => this.push(chunk));
    pack.on('error', err => this.emit('error', err));
  }

  addEntry(entry, opts) {
    if (this._processing) {
      return this._waitingEntries.push([ entry, opts ]);
    }

    opts = opts || {};
    this._processing = true;

    const entryType = utils.entryType(entry);
    if (!entryType) return; // TODO

    if (entryType === 'fileOrDir') {
      this._addFileOrDirEntry(entry, opts);
    } else if (entryType === 'buffer') {
      this._addBufferEntry(entry, opts);
    } else { // stream
      this._addStreamEntry(entry, opts);
    }

  }

  _addFileOrDirEntry(entry, opts) {
    fs.stat(entry, (err, stat) => {
      if (err) return this.emit('error', err);
      if (stat.isDirectory()) return this._addDirEntry(entry, opts);
      if (stat.isFile()) return this._addFileEntry(entry, opts);

      const illigalEntryError = new Error('Type is not supported, must be a file path, directory path, file buffer, or a readable stream');
      illigalEntryError.name = 'IlligalEntryError';
      this.emit('error', illigalEntryError);
    });
  }

  _addFileEntry(entry, opts) {
    // stat file to get file size
    fs.stat(entry, (err, stat) => {
      if (err) return this.emit('error', err);
      const entryStream = this._pack.entry({ name: opts.relativePath || path.basename(entry), size: stat.size, mode: stat.mode & 0o777 }, this._onEntryFinish.bind(this));
      const stream = fs.createReadStream(entry, opts.fs);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(entryStream);
    });
  }

  _addDirEntry(entry, opts) {
    fs.readdir(entry, (err, files) => {
      if (err) return this.emit('error', err);

      const relativePath = opts.relativePath || '';
      files.forEach(fileOrDir => {
        const newOpts = utils.clone(opts);
        if (opts.ignoreBase) {
          newOpts.relativePath = path.posix.join(relativePath, fileOrDir);
        } else {
          newOpts.relativePath = path.posix.join(relativePath, path.basename(entry), fileOrDir);
        }
        newOpts.ignoreBase = true;
        this.addEntry(path.posix.join(entry, fileOrDir), newOpts);
      });
      this._onEntryFinish();
    });
  }

  _addBufferEntry(entry, opts) {
    if (!opts.relativePath) return this.emit('error', 'opts.relativePath is required if entry is a buffer');
    this._pack.entry({ name: opts.relativePath }, entry, this._onEntryFinish.bind(this));
  }

  _addStreamEntry(entry, opts) {
    entry.on('error', err => this.emit('error', err));

    if (!opts.relativePath) return this.emit('error', new Error('opts.relativePath is required'));

    if (opts.size) {
      const entryStream = this._pack.entry({ name: opts.relativePath, size: opts.size }, this._onEntryFinish.bind(this));
      entry.pipe(entryStream);
    } else {
      if (!opts.suppressSizeWarning) {
        console.warn('You should specify the size of streamming data by opts.size to prevent all streaming data from loading into memory. If you are sure about memory cost, pass opts.suppressSizeWarning: true to suppress this warning');
      }
      const buf = [];
      const collectStream = new stream.Writable({
        write(chunk, _, callback) {
          buf.push(chunk);
          callback();
        },
      });
      collectStream.on('error', err => this.emit('error', err));
      collectStream.on('finish', () => {
        this._pack.entry({ name: opts.relativePath }, Buffer.concat(buf), this._onEntryFinish.bind(this));
      });
      entry.pipe(collectStream);
    }
  }

  _read() {}

  _onEntryFinish(err) {
    if (err) return this.emit('error', err);

    this._processing = false;
    const waitingEntry = this._waitingEntries.shift();
    if (waitingEntry) {
      this.addEntry.apply(this, waitingEntry);
    } else {
      this._finalize();
    }
  }

  _finalize() {
    this._pack.finalize();
  }
}

module.exports = TarStream;


code:
'use strict';

const fs = require('fs');
const tar = require('tar-stream');
const utils = require('../utils');
const streamifier = require('streamifier');

// stream.Writable
class TarUncompressStream extends tar.extract {
  constructor(opts) {
    opts = opts || {};
    super(opts);

    const sourceType = utils.sourceType(opts.source);

    if (sourceType === 'file') {
      const stream = fs.createReadStream(opts.source, opts.fs);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'buffer') {
      const stream = streamifier.createReadStream(opts.source, opts.streamifier);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'stream') {
      opts.source.on('error', err => this.emit('error', err));
      opts.source.pipe(this);
    }

    // else: waiting to be piped
  }
}

module.exports = TarUncompressStream;


code:
'use strict';

const tar = require('../tar');
const gzip = require('../gzip');
const utils = require('../utils');
const stream = require('stream');
const pump = require('pump');
const ready = require('get-ready');

class TgzFileStream extends stream.Transform {
  constructor(opts) {
    opts = opts || {};
    super(opts);

    const sourceType = this._sourceType = utils.sourceType(opts.source);

    const tarStream = this._tarStream = new tar.FileStream(opts);
    opts = utils.clone(opts);
    delete opts.source;
    const gzipStream = new gzip.FileStream(opts);

    gzipStream.on('data', chunk => {
      this.push(chunk);
    });
    gzipStream.on('end', () => this.ready(true));

    pump(tarStream, gzipStream, err => {
      err && this.emit('error', err);
    });

    if (sourceType !== 'stream' && sourceType !== undefined) {
      this.end();
    }
  }

  _transform(chunk, encoding, callback) {
    this._tarStream.write(chunk, encoding, callback);
  }

  _flush(callback) {
    if (this._sourceType === 'stream' || this._sourceType === undefined) {
      this._tarStream.end();
    }
    this.ready(callback);
  }
}

ready.mixin(TgzFileStream.prototype);
module.exports = TgzFileStream;


code:
'use strict';

const utils = require('../utils');
const TgzStream = require('./stream');
const TgzFileStream = require('./file_stream');
const TgzUncompressStream = require('./uncompress_stream');

exports.Stream = TgzStream;
exports.FileStream = TgzFileStream;
exports.UncompressStream = TgzUncompressStream;
exports.compressDir = utils.makeCompressDirFn(TgzStream);
exports.compressFile = utils.makeFileProcessFn(TgzFileStream);
exports.uncompress = utils.makeUncompressFn(TgzUncompressStream);
exports.decompress = utils.makeUncompressFn(TgzUncompressStream);


code:
'use strict';

const tar = require('../tar');
const gzip = require('../gzip');
const BaseStream = require('../base_stream');

class TgzStream extends BaseStream {
  constructor(opts) {
    super(opts);

    const tarStream = this._tarStream = new tar.Stream();
    tarStream.on('error', err => this.emit('error', err));

    const gzipStream = new gzip.FileStream();
    gzipStream.on('end', () => this.push(null));
    gzipStream.on('data', chunk => this.push(chunk));
    gzipStream.on('error', err => this.emit('error', err));

    tarStream.pipe(gzipStream);
  }

  addEntry(entry, opts) {
    this._tarStream.addEntry(entry, opts);
  }
}

module.exports = TgzStream;


code:
'use strict';

const fs = require('fs');
const utils = require('../utils');
const ready = require('get-ready');
const streamifier = require('streamifier');
const FlushWritable = require('flushwritable');
const GzipUncompressStream = require('../gzip').UncompressStream;
const TarUncompressStream = require('../tar').UncompressStream;

class TgzUncompressStream extends FlushWritable {
  constructor(opts) {
    opts = opts || {};
    super(opts);

    const newOpts = utils.clone(opts);
    newOpts.source = undefined;
    this._gzipStream = new GzipUncompressStream(newOpts)
      .on('error', err => this.emit('error', err));

    const tarStream = new TarUncompressStream(newOpts)
      .on('finish', () => this.ready(true))
      .on('entry', this.emit.bind(this, 'entry'))
      .on('error', err => this.emit('error', err));

    this._gzipStream.pipe(tarStream);

    const sourceType = utils.sourceType(opts.source);

    if (sourceType === 'file') {
      const stream = fs.createReadStream(opts.source, opts.fs);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'buffer') {
      const stream = streamifier.createReadStream(opts.source, opts.streamifier);
      stream.on('error', err => this.emit('error', err));
      stream.pipe(this);
      return;
    }

    if (sourceType === 'stream') {
      opts.source.on('error', err => this.emit('error', err));
      opts.source.pipe(this);
    }

    // else: waiting to be piped
  }

  _write(chunk, encoding, callback) {
    this._gzipStream.write(chunk, encoding, callback);
  }

  _flush(callback) {
    this._gzipStream.end();
    this.ready(callback);
  }
}

ready.mixin(TgzUncompressStream.prototype);

module.exports = TgzUncompressStream;


code:
'use strict';

const fs = require('fs');
const path = require('path');
const mkdirp = require('mkdirp');
const pump = require('pump');

// file/fileBuffer/stream
exports.sourceType = source => {
  if (!source) return undefined;

  if (source instanceof Buffer) return 'buffer';
  if (typeof source._read === 'function' || typeof source._transform === 'function') return 'stream';
  if (typeof source !== 'string') {
    const err = new Error('Type is not supported, must be a file path, file buffer, or a readable stream');
    err.name = 'IlligalSourceError';
    throw err;
  }

  return 'file';
};

function destType(dest) {
  if (typeof dest._write === 'function' || typeof dest._transform === 'function') return 'stream';
  if (typeof dest !== 'string') {
    const err = new Error('Type is not supported, must be a file path, or a writable stream');
    err.name = 'IlligalDestinationError';
    throw err;
  }
  return 'path';
}

exports.destType = destType;

const illigalEntryError = new Error('Type is not supported, must be a file path, directory path, file buffer, or a readable stream');
illigalEntryError.name = 'IlligalEntryError';

// fileOrDir/fileBuffer/stream
exports.entryType = entry => {
  if (!entry) return;

  if (entry instanceof Buffer) return 'buffer';
  if (typeof entry._read === 'function' || typeof entry._transform === 'function') return 'stream';
  if (typeof entry !== 'string') throw illigalEntryError;

  return 'fileOrDir';
};

exports.clone = obj => {
  const newObj = {};
  for (const i in obj) {
    newObj[i] = obj[i];
  }
  return newObj;
};

exports.makeFileProcessFn = StreamClass => {
  return (source, dest, opts) => {
    opts = opts || {};
    opts.source = source;
    const destStream = destType(dest) === 'path' ? fs.createWriteStream(dest) : dest;
    const compressStream = new StreamClass(opts);
    return safePipe([ compressStream, destStream ]);
  };
};

exports.makeCompressDirFn = StreamClass => {
  return (dir, dest, opts) => {
    const destStream = destType(dest) === 'path' ? fs.createWriteStream(dest) : dest;
    const compressStream = new StreamClass();
    compressStream.addEntry(dir, opts);
    return safePipe([ compressStream, destStream ]);
  };
};

exports.makeUncompressFn = StreamClass => {
  return (source, destDir, opts) => {
    opts = opts || {};
    opts.source = source;
    if (!source) { // !source 和 sourceType中返回undeined对应
      const error = new Error('Type is not supported, must be a file path, file buffer, or a readable stream');
      error.name = 'IlligalSourceError';
      throw error;
    }
    if (destType(destDir) !== 'path') {
      const error = new Error('uncompress destination must be a directory');
      error.name = 'IlligalDestError';
      throw error;
    }

    return new Promise((resolve, reject) => {
      mkdirp(destDir, err => {
        if (err) return reject(err);

        let entryCount = 0;
        let successCount = 0;
        let isFinish = false;
        function done() {
          // resolve when both stream finish and file write finish
          if (isFinish && entryCount === successCount) resolve();
        }

        new StreamClass(opts)
          .on('finish', () => {
            isFinish = true;
            done();
          })
          .on('error', reject)
          .on('entry', (header, stream, next) => {
            stream.on('end', next);

            if (header.type === 'file') {
              const fullpath = path.join(destDir, header.name);
              mkdirp(path.dirname(fullpath), err => {
                if (err) return reject(err);

                entryCount++;
                pump(stream, fs.createWriteStream(fullpath, { mode: opts.mode || header.mode }), err => {
                  if (err) return reject(err);
                  successCount++;
                  done();
                });
              });
            } else if (header.type === 'symlink') {
              // symlink
              const src = path.join(destDir, header.name);
              const target = path.resolve(path.dirname(src), header.linkname);
              entryCount++;
              fs.symlink(target, src, err => {
                if (err) return reject(err);
                successCount++;
                stream.resume();
              });
            } else { // directory
              mkdirp(path.join(destDir, header.name), err => {
                if (err) return reject(err);
                stream.resume();
              });
            }
          });
      });
    });
  };
};

exports.streamToBuffer = stream => {
  return new Promise((resolve, reject) => {
    const chunks = [];
    stream
      .on('readable', () => {
        let chunk;
        while ((chunk = stream.read())) chunks.push(chunk);
      })
      .on('end', () => resolve(Buffer.concat(chunks)))
      .on('error', err => reject(err));
  });
};

function safePipe(streams) {
  return new Promise((resolve, reject) => {
    pump(streams[0], streams[1], err => {
      if (err) return reject(err);
      resolve();
    });
  });
}

exports.safePipe = safePipe;

exports.stripFileName = (strip, fileName, type) => {
  // before
  // node/package.json
  // node/lib/index.js
  //
  // when strip 1
  // package.json
  // lib/index.js
  //
  // when strip 2
  // package.json
  // index.js
  if (Buffer.isBuffer(fileName)) fileName = fileName.toString();

  // use / instead of \\
  if (fileName.indexOf('\\') !== -1) fileName = fileName.replace(/\\+/g, '/');

  // fix absolute path
  // /foo => foo
  if (fileName[0] === '/') fileName = fileName.replace(/^\/+/, '');

  let s = fileName.split('/');

  // fix relative path
  // foo/../bar/../../asdf/
  //  => asdf/
  if (s.indexOf('..') !== -1) {
    fileName = path.normalize(fileName);
    // https://npm.taobao.org/mirrors/node/latest/docs/api/path.html#path_path_normalize_path
    if (process.platform === 'win32') fileName = fileName.replace(/\\+/g, '/');
    // replace '../' on ../../foo/bar
    fileName = fileName.replace(/(\.\.\/)+/, '');
    if (type === 'directory' && fileName && fileName[fileName.length - 1] !== '/') {
      fileName += '/';
    }
    s = fileName.split('/');
  }

  strip = Math.min(strip, s.length - 1);
  return s.slice(strip).join('/') || '/';
};


code:
'use strict';

const path = require('path');
const yazl = require('yazl');
const assert = require('assert');
const stream = require('stream');
const utils = require('../utils');
const ready = require('get-ready');

class ZipFileStream extends stream.Transform {
  constructor(opts) {
    super(opts);

    const sourceType = utils.sourceType(opts.source);

    const zipfile = new yazl.ZipFile();
    const zipStream = zipfile.outputStream;
    zipStream.on('data', data => this.push(data));
    zipStream.on('end', () => this.ready(true));
    zipfile.on('error', err => this.emit('error', err));

    if (sourceType !== 'file') {
      assert(opts.relativePath, 'opts.relativePath is required when compressing a buffer, or a stream');
    }

    if (sourceType) {
      this.end();
    }

    if (sourceType === 'file') {
      zipfile.addFile(opts.source, opts.relativePath || path.basename(opts.source), opts.yazl);
    } else if (sourceType === 'buffer') {
      zipfile.addBuffer(opts.source, opts.relativePath, opts.yazl);
    } else if (sourceType === 'stream') {
      zipfile.addReadStream(opts.source, opts.relativePath, opts.yazl);
    } else { // undefined
      const passThrough = this._passThrough = new stream.PassThrough();
      this.on('finish', () => passThrough.end());
      zipfile.addReadStream(passThrough, opts.relativePath, opts.yazl);
    }
    zipfile.end(opts.yazl);
  }

  _transform(chunk, encoding, callback) {
    if (this._passThrough) {
      this._passThrough.write(chunk, encoding, callback);
    }
  }

  _flush(callback) {
    this.ready(callback);
  }
}

ready.mixin(ZipFileStream.prototype);
module.exports = ZipFileStream;


code:
'use strict';

const utils = require('../utils');
const ZipStream = require('./stream');
const ZipFileStream = require('./file_stream');
const ZipUncompressStream = require('./uncompress_stream');

exports.Stream = ZipStream;
exports.FileStream = ZipFileStream;
exports.UncompressStream = ZipUncompressStream;
exports.compressDir = utils.makeCompressDirFn(ZipStream);
exports.compressFile = utils.makeFileProcessFn(ZipFileStream);
exports.uncompress = utils.makeUncompressFn(ZipUncompressStream);
exports.decompress = utils.makeUncompressFn(ZipUncompressStream);


code:
'use strict';

const path = require('path');
const yazl = require('yazl');
const TarStream = require('../tar/stream');

class ZipStream extends TarStream {
  _init() {
    const zipfile = this._zipfile = new yazl.ZipFile();
    const stream = zipfile.outputStream;
    stream.on('end', () => this.push(null));
    stream.on('data', chunk => this.push(chunk));
    stream.on('error', err => this.emit('error', err));
  }

  _addFileEntry(entry, opts) {
    this._zipfile.addFile(entry, opts.relativePath || path.basename(entry), opts);
    this._onEntryFinish();
  }

  _addBufferEntry(entry, opts) {
    if (!opts.relativePath) return this.emit('error', new Error('opts.relativePath is required if entry is a buffer'));
    this._zipfile.addBuffer(entry, opts.relativePath, opts);
    this._onEntryFinish();
  }

  _addStreamEntry(entry, opts) {
    if (!opts.relativePath) return this.emit('error', new Error('opts.relativePath is required if entry is a stream'));

    entry.on('error', err => this.emit('error', err));
    this._zipfile.addReadStream(entry, opts.relativePath, opts);
    this._onEntryFinish();
  }

  _finalize() {
    this._zipfile.end();
  }
}

module.exports = ZipStream;


code:
'use strict';

// https://github.com/thejoshwolfe/yauzl#no-streaming-unzip-api

const yauzl = require('@eggjs/yauzl');
const stream = require('stream');
const UncompressBaseStream = require('../base_write_stream');
const utils = require('../utils');

// lazy load iconv-lite
let iconv;

const YAUZL_CALLBACK = Symbol('ZipUncompressStream#yauzlCallback');
const STRIP_NAME = Symbol('ZipUncompressStream#stripName');

// don't decodeStrings on yauzl, we should handle fileName by ourself
// see validateFileName on https://github.com/thejoshwolfe/yauzl/blob/51010ce4e8c7e6345efe195e1b4150518f37b393/index.js#L607
//  - support "absolute path"
const DEFAULTS = { lazyEntries: true, decodeStrings: false };

// from: https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/zip.ts#L51
function modeFromEntry(entry) {
  const attr = entry.externalFileAttributes >> 16 || 33188;

  return [ 448 /* S_IRWXU */, 56 /* S_IRWXG */, 7 /* S_IRWXO */ ]
    .map(mask => attr & mask)
    .reduce((a, b) => a + b, attr & 61440 /* S_IFMT */);
}

class ZipUncompressStream extends UncompressBaseStream {
  constructor(opts) {
    opts = opts || {};
    super(opts);

    this._chunks = [];
    this._strip = Number(opts.strip) || 0;
    this._zipFileNameEncoding = opts.zipFileNameEncoding || 'utf8';
    if (this._zipFileNameEncoding === 'utf-8') {
      this._zipFileNameEncoding = 'utf8';
    }

    this[YAUZL_CALLBACK] = this[YAUZL_CALLBACK].bind(this);

    const sourceType = utils.sourceType(opts.source);

    const yauzlOpts = this._yauzlOpts = Object.assign({}, DEFAULTS, opts.yauzl);
    if (sourceType === 'file') {
      yauzl.open(opts.source, yauzlOpts, this[YAUZL_CALLBACK]);
      return;
    }

    if (sourceType === 'buffer') {
      yauzl.fromBuffer(opts.source, yauzlOpts, this[YAUZL_CALLBACK]);
      return;
    }

    if (sourceType === 'stream') {
      utils.streamToBuffer(opts.source)
        .then(buf => yauzl.fromBuffer(buf, yauzlOpts, this[YAUZL_CALLBACK]))
        .catch(e => this.emit('error', e));
      return;
    }

    this.on('pipe', srcStream => {
      srcStream.unpipe(srcStream);

      utils.streamToBuffer(srcStream)
        .then(buf => {
          this._chunks.push(buf);
          buf = Buffer.concat(this._chunks);
          yauzl.fromBuffer(buf, yauzlOpts, this[YAUZL_CALLBACK]);
        })
        .catch(e => this.emit('error', e));
    });
  }

  _write(chunk) {
    // push to _chunks array, this will only happen once, for stream will be unpiped.
    this._chunks.push(chunk);
  }

  [YAUZL_CALLBACK](err, zipFile) {
    if (err) return this.emit('error', err);

    zipFile.readEntry();

    zipFile
      .on('entry', entry => {
        const mode = modeFromEntry(entry);
        // fileName is buffer by default because decodeStrings = false
        if (Buffer.isBuffer(entry.fileName)) {
          if (this._zipFileNameEncoding === 'utf8') {
            entry.fileName = entry.fileName.toString();
          } else {
            if (!iconv) {
              iconv = require('iconv-lite');
            }
            entry.fileName = iconv.decode(entry.fileName, this._zipFileNameEncoding);
          }
        }
        // directory file names end with '/' (for Linux and macOS) or '\' (for Windows)
        const type = /[\\\/]$/.test(entry.fileName) ? 'directory' : 'file';
        const name = entry.fileName = this[STRIP_NAME](entry.fileName, type);

        const header = { name, type, yauzl: entry, mode };

        if (type === 'file') {
          zipFile.openReadStream(entry, (err, readStream) => {
            if (err) return this.emit('error', err);
            this.emit('entry', header, readStream, next);
          });
        } else { // directory
          const placeholder = new stream.Readable({ read() {} });
          this.emit('entry', header, placeholder, next);
          setImmediate(() => placeholder.emit('end'));
        }
      })
      .on('end', () => this.emit('finish'))
      .on('error', err => this.emit('error', err));

    function next() {
      zipFile.readEntry();
    }
  }

  [STRIP_NAME](fileName, type) {
    return utils.stripFileName(this._strip, fileName, type);
  }
}

module.exports = ZipUncompressStream;


compressing

description: Everything you need for compressing and uncompressing

contributor: git-contributor

test:js: egg-bin test --ts false

test: npm run test:js && npm run test:ts

cov: egg-bin cov --ts false

lint-fix: eslint . --fix

lint: eslint .

ci: npm run lint && npm run test:ts && npm run cov

keywords: compress uncompress util tgz gzip tar zip stream

author: shaoshuai0102 <shaoshuai0102@gmail.com>


code:
1.7.4 / 2019-03-18
==================

  * deps: compressible@~2.0.16
    - Mark `text/less` as compressible
    - deps: mime-db@'>= 1.38.0 < 2'
  * deps: on-headers@~1.0.2
    - Fix `res.writeHead` patch missing return value
  * perf: prevent unnecessary buffer copy

1.7.3 / 2018-07-15
==================

  * deps: accepts@~1.3.5
    - deps: mime-types@~2.1.18
  * deps: compressible@~2.0.14
    - Mark all XML-derived types as compressible
    - deps: mime-db@'>= 1.34.0 < 2'
  * deps: safe-buffer@5.1.2

1.7.2 / 2018-02-18
==================

  * deps: compressible@~2.0.13
    - deps: mime-db@'>= 1.33.0 < 2'

1.7.1 / 2017-09-26
==================

  * deps: accepts@~1.3.4
    - deps: mime-types@~2.1.16
  * deps: bytes@3.0.0
  * deps: compressible@~2.0.11
    - deps: mime-db@'>= 1.29.0 < 2'
  * deps: debug@2.6.9
  * deps: vary@~1.1.2
    - perf: improve header token parsing speed

1.7.0 / 2017-07-10
==================

  * Use `safe-buffer` for improved Buffer API
  * deps: bytes@2.5.0
  * deps: compressible@~2.0.10
    - Fix regex fallback to not override `compressible: false` in db
    - deps: mime-db@'>= 1.27.0 < 2'
  * deps: debug@2.6.8
    - Allow colors in workers
    - Deprecated `DEBUG_FD` environment variable set to `3` or higher
    - Fix error when running under React Native
    - Fix `DEBUG_MAX_ARRAY_LENGTH`
    - Use same color for same namespace
    - deps: ms@2.0.0
  * deps: vary@~1.1.1
    - perf: hoist regular expression

1.6.2 / 2016-05-12
==================

  * deps: accepts@~1.3.3
    - deps: mime-types@~2.1.11
    - deps: negotiator@0.6.1
  * deps: bytes@2.3.0
    - Drop partial bytes on all parsed units
    - Fix parsing byte string that looks like hex
    - perf: hoist regular expressions
  * deps: compressible@~2.0.8
    - deps: mime-db@'>= 1.23.0 < 2'

1.6.1 / 2016-01-19
==================

  * deps: bytes@2.2.0
  * deps: compressible@~2.0.7
    - deps: mime-db@'>= 1.21.0 < 2'
  * deps: accepts@~1.3.1
    - deps: mime-types@~2.1.9

1.6.0 / 2015-09-29
==================

  * Skip compression when response has `Cache-Control: no-transform`
  * deps: accepts@~1.3.0
    - deps: mime-types@~2.1.7
    - deps: negotiator@0.6.0
  * deps: compressible@~2.0.6
    - deps: mime-db@'>= 1.19.0 < 2'
  * deps: on-headers@~1.0.1
    - perf: enable strict mode
  * deps: vary@~1.1.0
    - Only accept valid field names in the `field` argument

1.5.2 / 2015-07-30
==================

  * deps: accepts@~1.2.12
    - deps: mime-types@~2.1.4
  * deps: compressible@~2.0.5
    - deps: mime-db@'>= 1.16.0 < 2'
  * deps: vary@~1.0.1
    - Fix setting empty header from empty `field`
    - perf: enable strict mode
    - perf: remove argument reassignments

1.5.1 / 2015-07-05
==================

  * deps: accepts@~1.2.10
    - deps: mime-types@~2.1.2
  * deps: compressible@~2.0.4
    - deps: mime-db@'>= 1.14.0 < 2'
    - perf: enable strict mode

1.5.0 / 2015-06-09
==================

  * Fix return value from `.end` and `.write` after end
  * Improve detection of zero-length body without `Content-Length`
  * deps: accepts@~1.2.9
    - deps: mime-types@~2.1.1
    - perf: avoid argument reassignment & argument slice
    - perf: avoid negotiator recursive construction
    - perf: enable strict mode
    - perf: remove unnecessary bitwise operator
  * deps: bytes@2.1.0
    - Slight optimizations
    - Units no longer case sensitive when parsing
  * deps: compressible@~2.0.3
    - Fix regex fallback to work if type exists, but is undefined
    - deps: mime-db@'>= 1.13.0 < 2'
    - perf: hoist regex declaration
    - perf: use regex to extract mime
  * perf: enable strict mode
  * perf: remove flush reassignment
  * perf: simplify threshold detection

1.4.4 / 2015-05-11
==================

  * deps: accepts@~1.2.7
    - deps: mime-types@~2.0.11
    - deps: negotiator@0.5.3
  * deps: debug@~2.2.0
    - deps: ms@0.7.1

1.4.3 / 2015-03-14
==================

  * deps: accepts@~1.2.5
    - deps: mime-types@~2.0.10
  * deps: debug@~2.1.3
    - Fix high intensity foreground color for bold
    - deps: ms@0.7.0

1.4.2 / 2015-03-11
==================

  * Fix error when code calls `res.end(str, encoding)`
    - Specific to Node.js 0.8
  * deps: debug@~2.1.2
    - deps: ms@0.7.0

1.4.1 / 2015-02-15
==================

  * deps: accepts@~1.2.4
    - deps: mime-types@~2.0.9
    - deps: negotiator@0.5.1

1.4.0 / 2015-02-01
==================

  * Prefer `gzip` over `deflate` on the server
    - Not all clients agree on what "deflate" coding means

1.3.1 / 2015-01-31
==================

  * deps: accepts@~1.2.3
    - deps: mime-types@~2.0.8
  * deps: compressible@~2.0.2
    - deps: mime-db@'>= 1.1.2 < 2'

1.3.0 / 2014-12-30
==================

  * Export the default `filter` function for wrapping
  * deps: accepts@~1.2.2
    - deps: mime-types@~2.0.7
    - deps: negotiator@0.5.0
  * deps: debug@~2.1.1

1.2.2 / 2014-12-10
==================

  * Fix `.end` to only proxy to `.end`
    - Fixes an issue with Node.js 0.11.14
  * deps: accepts@~1.1.4
    - deps: mime-types@~2.0.4

1.2.1 / 2014-11-23
==================

  * deps: accepts@~1.1.3
    - deps: mime-types@~2.0.3

1.2.0 / 2014-10-16
==================

  * deps: debug@~2.1.0
    - Implement `DEBUG_FD` env variable support

1.1.2 / 2014-10-15
==================

  * deps: accepts@~1.1.2
    - Fix error when media type has invalid parameter
    - deps: negotiator@0.4.9

1.1.1 / 2014-10-12
==================

  * deps: accepts@~1.1.1
    - deps: mime-types@~2.0.2
    - deps: negotiator@0.4.8
  * deps: compressible@~2.0.1
    - deps: mime-db@1.x

1.1.0 / 2014-09-07
==================

  * deps: accepts@~1.1.0
  * deps: compressible@~2.0.0
  * deps: debug@~2.0.0

1.0.11 / 2014-08-10
===================

  * deps: on-headers@~1.0.0
  * deps: vary@~1.0.0

1.0.10 / 2014-08-05
===================

  * deps: compressible@~1.1.1
    - Fix upper-case Content-Type characters prevent compression

1.0.9 / 2014-07-20
==================

  * Add `debug` messages
  * deps: accepts@~1.0.7
    - deps: negotiator@0.4.7

1.0.8 / 2014-06-20
==================

  * deps: accepts@~1.0.5
    - use `mime-types`

1.0.7 / 2014-06-11
==================

 * use vary module for better `Vary` behavior
 * deps: accepts@1.0.3
 * deps: compressible@1.1.0

1.0.6 / 2014-06-03
==================

 * fix regression when negotiation fails

1.0.5 / 2014-06-03
==================

 * fix listeners for delayed stream creation
   - fixes regression for certain `stream.pipe(res)` situations

1.0.4 / 2014-06-03
==================

 * fix adding `Vary` when value stored as array
 * fix back-pressure behavior
 * fix length check for `res.end`

1.0.3 / 2014-05-29
==================

 * use `accepts` for negotiation
 * use `on-headers` to handle header checking
 * deps: bytes@1.0.0

1.0.2 / 2014-04-29
==================

 * only version compatible with node.js 0.8
 * support headers given to `res.writeHead`
 * deps: bytes@0.3.0
 * deps: negotiator@0.4.3

1.0.1 / 2014-03-08
==================

 * bump negotiator
 * use compressible
 * use .headersSent (drops 0.8 support)
 * handle identity;q=0 case


code:
# compression

[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]

Node.js compression middleware.

The following compression codings are supported:

  - deflate
  - gzip

## Install

This is a [Node.js](https://nodejs.org/en/) module available through the
[npm registry](https://www.npmjs.com/). Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):

```bash
$ npm install compression
```

## API

<!-- eslint-disable no-unused-vars -->

```js
var compression = require('compression')
```

### compression([options])

Returns the compression middleware using the given `options`. The middleware
will attempt to compress response bodies for all request that traverse through
the middleware, based on the given `options`.

This middleware will never compress responses that include a `Cache-Control`
header with the [`no-transform` directive](https://tools.ietf.org/html/rfc7234#section-5.2.2.4),
as compressing will transform the body.

#### Options

`compression()` accepts these properties in the options object. In addition to
those listed below, [zlib](http://nodejs.org/api/zlib.html) options may be
passed in to the options object.

##### chunkSize

The default value is `zlib.Z_DEFAULT_CHUNK`, or `16384`.

See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning)
regarding the usage.

##### filter

A function to decide if the response should be considered for compression.
This function is called as `filter(req, res)` and is expected to return
`true` to consider the response for compression, or `false` to not compress
the response.

The default filter function uses the [compressible](https://www.npmjs.com/package/compressible)
module to determine if `res.getHeader('Content-Type')` is compressible.

##### level

The level of zlib compression to apply to responses. A higher level will result
in better compression, but will take longer to complete. A lower level will
result in less compression, but will be much faster.

This is an integer in the range of `0` (no compression) to `9` (maximum
compression). The special value `-1` can be used to mean the "default
compression level", which is a default compromise between speed and
compression (currently equivalent to level 6).

  - `-1` Default compression level (also `zlib.Z_DEFAULT_COMPRESSION`).
  - `0` No compression (also `zlib.Z_NO_COMPRESSION`).
  - `1` Fastest compression (also `zlib.Z_BEST_SPEED`).
  - `2`
  - `3`
  - `4`
  - `5`
  - `6` (currently what `zlib.Z_DEFAULT_COMPRESSION` points to).
  - `7`
  - `8`
  - `9` Best compression (also `zlib.Z_BEST_COMPRESSION`).

The default value is `zlib.Z_DEFAULT_COMPRESSION`, or `-1`.

**Note** in the list above, `zlib` is from `zlib = require('zlib')`.

##### memLevel

This specifies how much memory should be allocated for the internal compression
state and is an integer in the range of `1` (minimum level) and `9` (maximum
level).

The default value is `zlib.Z_DEFAULT_MEMLEVEL`, or `8`.

See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning)
regarding the usage.

##### strategy

This is used to tune the compression algorithm. This value only affects the
compression ratio, not the correctness of the compressed output, even if it
is not set appropriately.

  - `zlib.Z_DEFAULT_STRATEGY` Use for normal data.
  - `zlib.Z_FILTERED` Use for data produced by a filter (or predictor).
    Filtered data consists mostly of small values with a somewhat random
    distribution. In this case, the compression algorithm is tuned to
    compress them better. The effect is to force more Huffman coding and less
    string matching; it is somewhat intermediate between `zlib.Z_DEFAULT_STRATEGY`
    and `zlib.Z_HUFFMAN_ONLY`.
  - `zlib.Z_FIXED` Use to prevent the use of dynamic Huffman codes, allowing
    for a simpler decoder for special applications.
  - `zlib.Z_HUFFMAN_ONLY` Use to force Huffman encoding only (no string match).
  - `zlib.Z_RLE` Use to limit match distances to one (run-length encoding).
    This is designed to be almost as fast as `zlib.Z_HUFFMAN_ONLY`, but give
    better compression for PNG image data.

**Note** in the list above, `zlib` is from `zlib = require('zlib')`.

##### threshold

The byte threshold for the response body size before compression is considered
for the response, defaults to `1kb`. This is a number of bytes or any string
accepted by the [bytes](https://www.npmjs.com/package/bytes) module.

**Note** this is only an advisory setting; if the response size cannot be determined
at the time the response headers are written, then it is assumed the response is
_over_ the threshold. To guarantee the response size can be determined, be sure
set a `Content-Length` response header.

##### windowBits

The default value is `zlib.Z_DEFAULT_WINDOWBITS`, or `15`.

See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning)
regarding the usage.

#### .filter

The default `filter` function. This is used to construct a custom filter
function that is an extension of the default function.

```js
var compression = require('compression')
var express = require('express')

var app = express()
app.use(compression({ filter: shouldCompress }))

function shouldCompress (req, res) {
  if (req.headers['x-no-compression']) {
    // don't compress responses with this request header
    return false
  }

  // fallback to standard filter function
  return compression.filter(req, res)
}
```

### res.flush

This module adds a `res.flush()` method to force the partially-compressed
response to be flushed to the client.

## Examples

### express/connect

When using this module with express or connect, simply `app.use` the module as
high as you like. Requests that pass through the middleware will be compressed.

```js
var compression = require('compression')
var express = require('express')

var app = express()

// compress all responses
app.use(compression())

// add all routes
```

### Server-Sent Events

Because of the nature of compression this module does not work out of the box
with server-sent events. To compress content, a window of the output needs to
be buffered up in order to get good compression. Typically when using server-sent
events, there are certain block of data that need to reach the client.

You can achieve this by calling `res.flush()` when you need the data written to
actually make it to the client.

```js
var compression = require('compression')
var express = require('express')

var app = express()

// compress responses
app.use(compression())

// server-sent event stream
app.get('/events', function (req, res) {
  res.setHeader('Content-Type', 'text/event-stream')
  res.setHeader('Cache-Control', 'no-cache')

  // send a ping approx every 2 seconds
  var timer = setInterval(function () {
    res.write('data: ping\n\n')

    // !!! this is the important part
    res.flush()
  }, 2000)

  res.on('close', function () {
    clearInterval(timer)
  })
})
```

## License

[MIT](LICENSE)

[npm-image]: https://img.shields.io/npm/v/compression.svg
[npm-url]: https://npmjs.org/package/compression
[travis-image]: https://img.shields.io/travis/expressjs/compression/master.svg
[travis-url]: https://travis-ci.org/expressjs/compression
[coveralls-image]: https://img.shields.io/coveralls/expressjs/compression/master.svg
[coveralls-url]: https://coveralls.io/r/expressjs/compression?branch=master
[downloads-image]: https://img.shields.io/npm/dm/compression.svg
[downloads-url]: https://npmjs.org/package/compression