code:
# get-stream [![Build Status](https://travis-ci.org/sindresorhus/get-stream.svg?branch=master)](https://travis-ci.org/sindresorhus/get-stream)

> Get a stream as a string, buffer, or array

## Install

```
$ npm install --save get-stream
```

## Usage

```js
const fs = require('fs');
const getStream = require('get-stream');
const stream = fs.createReadStream('unicorn.txt');

getStream(stream).then(str => {
	console.log(str);
	/*
	              ,,))))))));,
	           __)))))))))))))),
	\|/       -\(((((''''((((((((.
	-*-==//////((''  .     `)))))),
	/|\      ))| o    ;-.    '(((((                                  ,(,
	         ( `|    /  )    ;))))'                               ,_))^;(~
	            |   |   |   ,))((((_     _____------~~~-.        %,;(;(>';'~
	            o_);   ;    )))(((` ~---~  `::           \      %%~~)(v;(`('~
	                  ;    ''''````         `:       `:::|\,__,%%    );`'; ~
	                 |   _                )     /      `:|`----'     `-'
	           ______/\/~    |                 /        /
	         /~;;.____/;;'  /          ___--,-(   `;;;/
	        / //  _;______;'------~~~~~    /;;/\    /
	       //  | |                        / ;   \;;,\
	      (<_  | ;                      /',/-----'  _>
	       \_| ||_                     //~;~~~~~~~~~
	           `\_|                   (,~~
	                                   \~\
	                                    ~~
	*/
});
```

## API

The methods returns a promise that resolves when the `end` event fires on the stream, indicating that there is no more data to be read. The stream is switched to flowing mode.

### getStream(stream, [options])

Get the `stream` as a string.

#### options

##### encoding

Type: `string`<br>
Default: `utf8`

[Encoding](https://nodejs.org/api/buffer.html#buffer_buffer) of the incoming stream.

##### maxBuffer

Type: `number`<br>
Default: `Infinity`

Maximum length of the returned string. If it exceeds this value before the stream ends, the promise will be rejected.

### getStream.buffer(stream, [options])

Get the `stream` as a buffer.

It honors the `maxBuffer` option as above, but it refers to byte length rather than string length.

### getStream.array(stream, [options])

Get the `stream` as an array of values.

It honors both the `maxBuffer` and `encoding` options. The behavior changes slightly based on the encoding chosen:

- When `encoding` is unset, it assumes an [object mode stream](https://nodesource.com/blog/understanding-object-streams/) and collects values emitted from `stream` unmodified. In this case `maxBuffer` refers to the number of items in the array (not the sum of their sizes).

- When `encoding` is set to `buffer`, it collects an array of buffers. `maxBuffer` refers to the summed byte lengths of every buffer in the array.

- When `encoding` is set to anything else, it collects an array of strings. `maxBuffer` refers to the summed character lengths of every string in the array.

## Errors

If the input stream emits an `error` event, the promise will be rejected with the error. The buffered data will be attached to the `bufferedData` property of the error.

```js
getStream(streamThatErrorsAtTheEnd('unicorn'))
	.catch(err => {
		console.log(err.bufferedData);
		//=> 'unicorn'
	});
```

## FAQ

### How is this different from [`concat-stream`](https://github.com/maxogden/concat-stream)?

This module accepts a stream instead of being one and returns a promise instead of using a callback. The API is simpler and it only supports returning a string, buffer, or array. It doesn't have a fragile type inference. You explicitly choose what you want. And it doesn't depend on the huge `readable-stream` package.

## Related

- [get-stdin](https://github.com/sindresorhus/get-stdin) - Get stdin as a string or buffer

## License

MIT © [Sindre Sorhus](https://sindresorhus.com)


code:
# lru cache

A cache object that deletes the least-recently-used items.

[![Build Status](https://travis-ci.org/isaacs/node-lru-cache.svg?branch=master)](https://travis-ci.org/isaacs/node-lru-cache) [![Coverage Status](https://coveralls.io/repos/isaacs/node-lru-cache/badge.svg?service=github)](https://coveralls.io/github/isaacs/node-lru-cache)

## Installation:

```javascript
npm install lru-cache --save
```

## Usage:

```javascript
var LRU = require("lru-cache")
  , options = { max: 500
              , length: function (n, key) { return n * 2 + key.length }
              , dispose: function (key, n) { n.close() }
              , maxAge: 1000 * 60 * 60 }
  , cache = LRU(options)
  , otherCache = LRU(50) // sets just the max size

cache.set("key", "value")
cache.get("key") // "value"

// non-string keys ARE fully supported
// but note that it must be THE SAME object, not
// just a JSON-equivalent object.
var someObject = { a: 1 }
cache.set(someObject, 'a value')
// Object keys are not toString()-ed
cache.set('[object Object]', 'a different value')
assert.equal(cache.get(someObject), 'a value')
// A similar object with same keys/values won't work,
// because it's a different object identity
assert.equal(cache.get({ a: 1 }), undefined)

cache.reset()    // empty the cache
```

If you put more stuff in it, then items will fall out.

If you try to put an oversized thing in it, then it'll fall out right
away.

## Options

* `max` The maximum size of the cache, checked by applying the length
  function to all values in the cache.  Not setting this is kind of
  silly, since that's the whole purpose of this lib, but it defaults
  to `Infinity`.
* `maxAge` Maximum age in ms.  Items are not pro-actively pruned out
  as they age, but if you try to get an item that is too old, it'll
  drop it and return undefined instead of giving it to you.
* `length` Function that is used to calculate the length of stored
  items.  If you're storing strings or buffers, then you probably want
  to do something like `function(n, key){return n.length}`.  The default is
  `function(){return 1}`, which is fine if you want to store `max`
  like-sized things.  The item is passed as the first argument, and
  the key is passed as the second argumnet.
* `dispose` Function that is called on items when they are dropped
  from the cache.  This can be handy if you want to close file
  descriptors or do other cleanup tasks when items are no longer
  accessible.  Called with `key, value`.  It's called *before*
  actually removing the item from the internal cache, so if you want
  to immediately put it back in, you'll have to do that in a
  `nextTick` or `setTimeout` callback or it won't do anything.
* `stale` By default, if you set a `maxAge`, it'll only actually pull
  stale items out of the cache when you `get(key)`.  (That is, it's
  not pre-emptively doing a `setTimeout` or anything.)  If you set
  `stale:true`, it'll return the stale value before deleting it.  If
  you don't set this, then it'll return `undefined` when you try to
  get a stale entry, as if it had already been deleted.
* `noDisposeOnSet` By default, if you set a `dispose()` method, then
  it'll be called whenever a `set()` operation overwrites an existing
  key.  If you set this option, `dispose()` will only be called when a
  key falls out of the cache, not when it is overwritten.

## API

* `set(key, value, maxAge)`
* `get(key) => value`

    Both of these will update the "recently used"-ness of the key.
    They do what you think. `maxAge` is optional and overrides the
    cache `maxAge` option if provided.

    If the key is not found, `get()` will return `undefined`.

    The key and val can be any value.

* `peek(key)`

    Returns the key value (or `undefined` if not found) without
    updating the "recently used"-ness of the key.

    (If you find yourself using this a lot, you *might* be using the
    wrong sort of data structure, but there are some use cases where
    it's handy.)

* `del(key)`

    Deletes a key out of the cache.

* `reset()`

    Clear the cache entirely, throwing away all values.

* `has(key)`

    Check if a key is in the cache, without updating the recent-ness
    or deleting it for being stale.

* `forEach(function(value,key,cache), [thisp])`

    Just like `Array.prototype.forEach`.  Iterates over all the keys
    in the cache, in order of recent-ness.  (Ie, more recently used
    items are iterated over first.)

* `rforEach(function(value,key,cache), [thisp])`

    The same as `cache.forEach(...)` but items are iterated over in
    reverse order.  (ie, less recently used items are iterated over
    first.)

* `keys()`

    Return an array of the keys in the cache.

* `values()`

    Return an array of the values in the cache.

* `length`

    Return total length of objects in cache taking into account
    `length` options function.

* `itemCount`

    Return total quantity of objects currently in cache. Note, that
    `stale` (see options) items are returned as part of this item
    count.

* `dump()`

    Return an array of the cache entries ready for serialization and usage
    with 'destinationCache.load(arr)`.

* `load(cacheEntriesArray)`

    Loads another cache entries array, obtained with `sourceCache.dump()`,
    into the cache. The destination cache is reset before loading new entries

* `prune()`

    Manually iterates over the entire cache proactively pruning old entries

license: mit


code:
'use strict'

module.exports = LRUCache

// This will be a proper iterable 'Map' in engines that support it,
// or a fakey-fake PseudoMap in older versions.
var Map = require('pseudomap')
var util = require('util')

// A linked list to keep track of recently-used-ness
var Yallist = require('yallist')

// use symbols if possible, otherwise just _props
var hasSymbol = typeof Symbol === 'function' && process.env._nodeLRUCacheForceNoSymbol !== '1'
var makeSymbol
if (hasSymbol) {
  makeSymbol = function (key) {
    return Symbol(key)
  }
} else {
  makeSymbol = function (key) {
    return '_' + key
  }
}

var MAX = makeSymbol('max')
var LENGTH = makeSymbol('length')
var LENGTH_CALCULATOR = makeSymbol('lengthCalculator')
var ALLOW_STALE = makeSymbol('allowStale')
var MAX_AGE = makeSymbol('maxAge')
var DISPOSE = makeSymbol('dispose')
var NO_DISPOSE_ON_SET = makeSymbol('noDisposeOnSet')
var LRU_LIST = makeSymbol('lruList')
var CACHE = makeSymbol('cache')

function naiveLength () { return 1 }

// lruList is a yallist where the head is the youngest
// item, and the tail is the oldest.  the list contains the Hit
// objects as the entries.
// Each Hit object has a reference to its Yallist.Node.  This
// never changes.
//
// cache is a Map (or PseudoMap) that matches the keys to
// the Yallist.Node object.
function LRUCache (options) {
  if (!(this instanceof LRUCache)) {
    return new LRUCache(options)
  }

  if (typeof options === 'number') {
    options = { max: options }
  }

  if (!options) {
    options = {}
  }

  var max = this[MAX] = options.max
  // Kind of weird to have a default max of Infinity, but oh well.
  if (!max ||
      !(typeof max === 'number') ||
      max <= 0) {
    this[MAX] = Infinity
  }

  var lc = options.length || naiveLength
  if (typeof lc !== 'function') {
    lc = naiveLength
  }
  this[LENGTH_CALCULATOR] = lc

  this[ALLOW_STALE] = options.stale || false
  this[MAX_AGE] = options.maxAge || 0
  this[DISPOSE] = options.dispose
  this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
  this.reset()
}

// resize the cache when the max changes.
Object.defineProperty(LRUCache.prototype, 'max', {
  set: function (mL) {
    if (!mL || !(typeof mL === 'number') || mL <= 0) {
      mL = Infinity
    }
    this[MAX] = mL
    trim(this)
  },
  get: function () {
    return this[MAX]
  },
  enumerable: true
})

Object.defineProperty(LRUCache.prototype, 'allowStale', {
  set: function (allowStale) {
    this[ALLOW_STALE] = !!allowStale
  },
  get: function () {
    return this[ALLOW_STALE]
  },
  enumerable: true
})

Object.defineProperty(LRUCache.prototype, 'maxAge', {
  set: function (mA) {
    if (!mA || !(typeof mA === 'number') || mA < 0) {
      mA = 0
    }
    this[MAX_AGE] = mA
    trim(this)
  },
  get: function () {
    return this[MAX_AGE]
  },
  enumerable: true
})

// resize the cache when the lengthCalculator changes.
Object.defineProperty(LRUCache.prototype, 'lengthCalculator', {
  set: function (lC) {
    if (typeof lC !== 'function') {
      lC = naiveLength
    }
    if (lC !== this[LENGTH_CALCULATOR]) {
      this[LENGTH_CALCULATOR] = lC
      this[LENGTH] = 0
      this[LRU_LIST].forEach(function (hit) {
        hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
        this[LENGTH] += hit.length
      }, this)
    }
    trim(this)
  },
  get: function () { return this[LENGTH_CALCULATOR] },
  enumerable: true
})

Object.defineProperty(LRUCache.prototype, 'length', {
  get: function () { return this[LENGTH] },
  enumerable: true
})

Object.defineProperty(LRUCache.prototype, 'itemCount', {
  get: function () { return this[LRU_LIST].length },
  enumerable: true
})

LRUCache.prototype.rforEach = function (fn, thisp) {
  thisp = thisp || this
  for (var walker = this[LRU_LIST].tail; walker !== null;) {
    var prev = walker.prev
    forEachStep(this, fn, walker, thisp)
    walker = prev
  }
}

function forEachStep (self, fn, node, thisp) {
  var hit = node.value
  if (isStale(self, hit)) {
    del(self, node)
    if (!self[ALLOW_STALE]) {
      hit = undefined
    }
  }
  if (hit) {
    fn.call(thisp, hit.value, hit.key, self)
  }
}

LRUCache.prototype.forEach = function (fn, thisp) {
  thisp = thisp || this
  for (var walker = this[LRU_LIST].head; walker !== null;) {
    var next = walker.next
    forEachStep(this, fn, walker, thisp)
    walker = next
  }
}

LRUCache.prototype.keys = function () {
  return this[LRU_LIST].toArray().map(function (k) {
    return k.key
  }, this)
}

LRUCache.prototype.values = function () {
  return this[LRU_LIST].toArray().map(function (k) {
    return k.value
  }, this)
}

LRUCache.prototype.reset = function () {
  if (this[DISPOSE] &&
      this[LRU_LIST] &&
      this[LRU_LIST].length) {
    this[LRU_LIST].forEach(function (hit) {
      this[DISPOSE](hit.key, hit.value)
    }, this)
  }

  this[CACHE] = new Map() // hash of items by key
  this[LRU_LIST] = new Yallist() // list of items in order of use recency
  this[LENGTH] = 0 // length of items in the list
}

LRUCache.prototype.dump = function () {
  return this[LRU_LIST].map(function (hit) {
    if (!isStale(this, hit)) {
      return {
        k: hit.key,
        v: hit.value,
        e: hit.now + (hit.maxAge || 0)
      }
    }
  }, this).toArray().filter(function (h) {
    return h
  })
}

LRUCache.prototype.dumpLru = function () {
  return this[LRU_LIST]
}

/* istanbul ignore next */
LRUCache.prototype.inspect = function (n, opts) {
  var str = 'LRUCache {'
  var extras = false

  var as = this[ALLOW_STALE]
  if (as) {
    str += '\n  allowStale: true'
    extras = true
  }

  var max = this[MAX]
  if (max && max !== Infinity) {
    if (extras) {
      str += ','
    }
    str += '\n  max: ' + util.inspect(max, opts)
    extras = true
  }

  var maxAge = this[MAX_AGE]
  if (maxAge) {
    if (extras) {
      str += ','
    }
    str += '\n  maxAge: ' + util.inspect(maxAge, opts)
    extras = true
  }

  var lc = this[LENGTH_CALCULATOR]
  if (lc && lc !== naiveLength) {
    if (extras) {
      str += ','
    }
    str += '\n  length: ' + util.inspect(this[LENGTH], opts)
    extras = true
  }

  var didFirst = false
  this[LRU_LIST].forEach(function (item) {
    if (didFirst) {
      str += ',\n  '
    } else {
      if (extras) {
        str += ',\n'
      }
      didFirst = true
      str += '\n  '
    }
    var key = util.inspect(item.key).split('\n').join('\n  ')
    var val = { value: item.value }
    if (item.maxAge !== maxAge) {
      val.maxAge = item.maxAge
    }
    if (lc !== naiveLength) {
      val.length = item.length
    }
    if (isStale(this, item)) {
      val.stale = true
    }

    val = util.inspect(val, opts).split('\n').join('\n  ')
    str += key + ' => ' + val
  })

  if (didFirst || extras) {
    str += '\n'
  }
  str += '}'

  return str
}

LRUCache.prototype.set = function (key, value, maxAge) {
  maxAge = maxAge || this[MAX_AGE]

  var now = maxAge ? Date.now() : 0
  var len = this[LENGTH_CALCULATOR](value, key)

  if (this[CACHE].has(key)) {
    if (len > this[MAX]) {
      del(this, this[CACHE].get(key))
      return false
    }

    var node = this[CACHE].get(key)
    var item = node.value

    // dispose of the old one before overwriting
    // split out into 2 ifs for better coverage tracking
    if (this[DISPOSE]) {
      if (!this[NO_DISPOSE_ON_SET]) {
        this[DISPOSE](key, item.value)
      }
    }

    item.now = now
    item.maxAge = maxAge
    item.value = value
    this[LENGTH] += len - item.length
    item.length = len
    this.get(key)
    trim(this)
    return true
  }

  var hit = new Entry(key, value, len, now, maxAge)

  // oversized objects fall out of cache automatically.
  if (hit.length > this[MAX]) {
    if (this[DISPOSE]) {
      this[DISPOSE](key, value)
    }
    return false
  }

  this[LENGTH] += hit.length
  this[LRU_LIST].unshift(hit)
  this[CACHE].set(key, this[LRU_LIST].head)
  trim(this)
  return true
}

LRUCache.prototype.has = function (key) {
  if (!this[CACHE].has(key)) return false
  var hit = this[CACHE].get(key).value
  if (isStale(this, hit)) {
    return false
  }
  return true
}

LRUCache.prototype.get = function (key) {
  return get(this, key, true)
}

LRUCache.prototype.peek = function (key) {
  return get(this, key, false)
}

LRUCache.prototype.pop = function () {
  var node = this[LRU_LIST].tail
  if (!node) return null
  del(this, node)
  return node.value
}

LRUCache.prototype.del = function (key) {
  del(this, this[CACHE].get(key))
}

LRUCache.prototype.load = function (arr) {
  // reset the cache
  this.reset()

  var now = Date.now()
  // A previous serialized cache has the most recent items first
  for (var l = arr.length - 1; l >= 0; l--) {
    var hit = arr[l]
    var expiresAt = hit.e || 0
    if (expiresAt === 0) {
      // the item was created without expiration in a non aged cache
      this.set(hit.k, hit.v)
    } else {
      var maxAge = expiresAt - now
      // dont add already expired items
      if (maxAge > 0) {
        this.set(hit.k, hit.v, maxAge)
      }
    }
  }
}

LRUCache.prototype.prune = function () {
  var self = this
  this[CACHE].forEach(function (value, key) {
    get(self, key, false)
  })
}

function get (self, key, doUse) {
  var node = self[CACHE].get(key)
  if (node) {
    var hit = node.value
    if (isStale(self, hit)) {
      del(self, node)
      if (!self[ALLOW_STALE]) hit = undefined
    } else {
      if (doUse) {
        self[LRU_LIST].unshiftNode(node)
      }
    }
    if (hit) hit = hit.value
  }
  return hit
}

function isStale (self, hit) {
  if (!hit || (!hit.maxAge && !self[MAX_AGE])) {
    return false
  }
  var stale = false
  var diff = Date.now() - hit.now
  if (hit.maxAge) {
    stale = diff > hit.maxAge
  } else {
    stale = self[MAX_AGE] && (diff > self[MAX_AGE])
  }
  return stale
}

function trim (self) {
  if (self[LENGTH] > self[MAX]) {
    for (var walker = self[LRU_LIST].tail;
      self[LENGTH] > self[MAX] && walker !== null;) {
      // We know that we're about to delete this one, and also
      // what the next least recently used key will be, so just
      // go ahead and set it now.
      var prev = walker.prev
      del(self, walker)
      walker = prev
    }
  }
}

function del (self, node) {
  if (node) {
    var hit = node.value
    if (self[DISPOSE]) {
      self[DISPOSE](hit.key, hit.value)
    }
    self[LENGTH] -= hit.length
    self[CACHE].delete(hit.key)
    self[LRU_LIST].removeNode(node)
  }
}

// classy, since V8 prefers predictable objects.
function Entry (key, value, length, now, maxAge) {
  this.key = key
  this.value = value
  this.length = length
  this.now = now
  this.maxAge = maxAge || 0
}


lru-cache

description: A cache object that deletes the least-recently-used items.

author: Isaac Z. Schlueter <i@izs.me>

keywords: mru lru cache

test: tap test/*.js --100 -J

snap: TAP_SNAPSHOT=1 tap test/*.js -J

posttest: standard test/*.js index.js

coveragerport: tap --coverage-report=html

lintfix: standard --fix test/*.js index.js

preversion: npm test

postversion: npm publish --tag=legacy

postpublish: git push origin --all; git push origin --tags

license: ISC


code:
# normalize-path [![NPM version](https://badge.fury.io/js/normalize-path.svg)](http://badge.fury.io/js/normalize-path)

> Normalize file path slashes to be unix-like forward slashes. Also condenses repeat slashes to a single slash and removes and trailing slashes.

## Install with [npm](npmjs.org)

```bash
npm i normalize-path --save
```

## Usage

```js
var normalize = require('normalize-path');

normalize('\\foo\\bar\\baz\\');
//=> '/foo/bar/baz'

normalize('./foo/bar/baz/');
//=> './foo/bar/baz'
```

Pass `false` as the last argument to **not** strip trailing slashes:

```js
normalize('./foo/bar/baz/', false);
//=> './foo/bar/baz/'

normalize('foo\\bar\\baz\\', false);
//=> 'foo/bar/baz/'
```

## Run tests

```bash
npm i -d && npm test
```

## Contributing
Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/jonschlinkert/normalize-path/issues).

## Author

**Jon Schlinkert**

+ [github/jonschlinkert](https://github.com/jonschlinkert)
+ [twitter/jonschlinkert](http://twitter.com/jonschlinkert)

## License
Copyright (c) 2015 Jon Schlinkert
Released under the MIT license

***

_This file was generated by [verb](https://github.com/assemble/verb) on January 23, 2015._


code:
/*!
 * normalize-path <https://github.com/jonschlinkert/normalize-path>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT License
 */

module.exports = function(fp, stripTrailing) {
  fp = fp.replace(/[\\\/]+/g, '/');
  if (stripTrailing === false) {
    return fp;
  }

  return fp.slice(-1) === '/'
    ? fp.slice(0, fp.length -1)
    : fp;
};


normalize-path

description: Normalize file path slashes to be unix-like forward slashes. Also condenses repeat slashes to a single slash and removes and trailing slashes.

type: git

type: MIT

test: mocha -R spec

keywords: file filepath fp normalize path slash slashes trailing unix


code:
'use strict';
var shebangRegex = require('shebang-regex');

module.exports = function (str) {
	var match = str.match(shebangRegex);

	if (!match) {
		return null;
	}

	var arr = match[0].replace(/#! ?/, '').split(' ');
	var bin = arr[0].split('/').pop();
	var arg = arr[1];

	return (bin === 'env' ?
		arg :
		bin + (arg ? ' ' + arg : '')
	);
};


shebang-command

description: Get the command from a shebang

license: MIT

repository: kevva/shebang-command

test: xo && ava

keywords: cmd command parse shebang


code:
# shebang-command [![Build Status](https://travis-ci.org/kevva/shebang-command.svg?branch=master)](https://travis-ci.org/kevva/shebang-command)

> Get the command from a shebang

## Install

```
$ npm install --save shebang-command
```

## Usage

```js
const shebangCommand = require('shebang-command');

shebangCommand('#!/usr/bin/env node');
//=> 'node'

shebangCommand('#!/bin/bash');
//=> 'bash'
```

## API

### shebangCommand(string)

#### string

Type: `string`

String containing a shebang.

## License

MIT © [Kevin Martensson](http://github.com/kevva)


code:
'use strict';
module.exports = /^#!.*/;


shebang-regex

description: Regular expression for matching a shebang

repository: sindresorhus/shebang-regex

test: node test.js

keywords: re regex regexp shebang match test


code:
# shebang-regex [![Build Status](https://travis-ci.org/sindresorhus/shebang-regex.svg?branch=master)](https://travis-ci.org/sindresorhus/shebang-regex)

> Regular expression for matching a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix))

## Install

```
$ npm install --save shebang-regex
```

## Usage

```js
var shebangRegex = require('shebang-regex');
var str = '#!/usr/bin/env node\nconsole.log("unicorns");';

shebangRegex.test(str);
//=> true

shebangRegex.exec(str)[0];
//=> '#!/usr/bin/env node'
```

## License

MIT © [Sindre Sorhus](http://sindresorhus.com)


code:
# Changes

## 1.3.1

* update deps
* update travis

## v1.3.0

* Add nothrow option to which.sync
* update tap

## v1.2.14

* appveyor: drop node 5 and 0.x
* travis-ci: add node 6, drop 0.x

## v1.2.13

* test: Pass missing option to pass on windows
* update tap
* update isexe to 2.0.0
* neveragain.tech pledge request

## v1.2.12

* Removed unused require

## v1.2.11

* Prevent changelog script from being included in package

## v1.2.10

* Use env.PATH only, not env.Path

## v1.2.9

* fix for paths starting with ../
* Remove unused `is-absolute` module

## v1.2.8

* bullet items in changelog that contain (but don't start with) #

## v1.2.7

* strip 'update changelog' changelog entries out of changelog

## v1.2.6

* make the changelog bulleted

## v1.2.5

* make a changelog, and keep it up to date
* don't include tests in package
* Properly handle relative-path executables
* appveyor
* Attach error code to Not Found error
* Make tests pass on Windows

## v1.2.4

* Fix typo

## v1.2.3

* update isexe, fix regression in pathExt handling

## v1.2.2

* update deps, use isexe module, test windows

## v1.2.1

* Sometimes windows PATH entries are quoted
* Fixed a bug in the check for group and user mode bits. This bug was introduced during refactoring for supporting strict mode.
* doc cli

## v1.2.0

* Add support for opt.all and -as cli flags
* test the bin
* update travis
* Allow checking for multiple programs in bin/which
* tap 2

## v1.1.2

* travis
* Refactored and fixed undefined error on Windows
* Support strict mode

## v1.1.1

* test +g exes against secondary groups, if available
* Use windows exe semantics on cygwin & msys
* cwd should be first in path on win32, not last
* Handle lower-case 'env.Path' on Windows
* Update docs
* use single-quotes

## v1.1.0

* Add tests, depend on is-absolute

## v1.0.9

* which.js: root is allowed to execute files owned by anyone

## v1.0.8

* don't use graceful-fs

## v1.0.7

* add license to package.json

## v1.0.6

* isc license

## 1.0.5

* Awful typo

## 1.0.4

* Test for path absoluteness properly
* win: Allow '' as a pathext if cmd has a . in it

## 1.0.3

* Remove references to execPath
* Make `which.sync()` work on Windows by honoring the PATHEXT variable.
* Make `isExe()` always return true on Windows.
* MIT

## 1.0.2

* Only files can be exes

## 1.0.1

* Respect the PATHEXT env for win32 support
* should 0755 the bin
* binary
* guts
* package
* 1st


code:
# which

Like the unix `which` utility.

Finds the first instance of a specified executable in the PATH
environment variable.  Does not cache the results, so `hash -r` is not
needed when the PATH changes.

## USAGE

```javascript
var which = require('which')

// async usage
which('node', function (er, resolvedPath) {
  // er is returned if no "node" is found on the PATH
  // if it is found, then the absolute path to the exec is returned
})

// sync usage
// throws if not found
var resolved = which.sync('node')

// if nothrow option is used, returns null if not found
resolved = which.sync('node', {nothrow: true})

// Pass options to override the PATH and PATHEXT environment vars.
which('node', { path: someOtherPath }, function (er, resolved) {
  if (er)
    throw er
  console.log('found at %j', resolved)
})
```

## CLI USAGE

Same as the BSD `which(1)` binary.

```
usage: which [-as] program ...
```

## OPTIONS

You may pass an options object as the second argument.

- `path`: Use instead of the `PATH` environment variable.
- `pathExt`: Use instead of the `PATHEXT` environment variable.
- `all`: Return all matches, instead of just the first one.  Note that
  this means the function returns an array of strings instead of a
  single string.


code:
#!/usr/bin/env node
var which = require("../")
if (process.argv.length < 3)
  usage()

function usage () {
  console.error('usage: which [-as] program ...')
  process.exit(1)
}

var all = false
var silent = false
var dashdash = false
var args = process.argv.slice(2).filter(function (arg) {
  if (dashdash || !/^-/.test(arg))
    return true

  if (arg === '--') {
    dashdash = true
    return false
  }

  var flags = arg.substr(1).split('')
  for (var f = 0; f < flags.length; f++) {
    var flag = flags[f]
    switch (flag) {
      case 's':
        silent = true
        break
      case 'a':
        all = true
        break
      default:
        console.error('which: illegal option -- ' + flag)
        usage()
    }
  }
  return false
})

process.exit(args.reduce(function (pv, current) {
  try {
    var f = which.sync(current, { all: all })
    if (all)
      f = f.join('\n')
    if (!silent)
      console.log(f)
    return pv;
  } catch (e) {
    return 1;
  }
}, 0))


which

author: Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me)

description: Like which(1) unix command. Find the first instance of an executable in the PATH.

test: tap test/*.js --cov

changelog: bash gen-changelog.sh

postversion: npm run changelog && git add CHANGELOG.md && git commit -m 'update changelog - '${npm_package_version}


code:
module.exports = which
which.sync = whichSync

var isWindows = process.platform === 'win32' ||
    process.env.OSTYPE === 'cygwin' ||
    process.env.OSTYPE === 'msys'

var path = require('path')
var COLON = isWindows ? ';' : ':'
var isexe = require('isexe')

function getNotFoundError (cmd) {
  var er = new Error('not found: ' + cmd)
  er.code = 'ENOENT'

  return er
}

function getPathInfo (cmd, opt) {
  var colon = opt.colon || COLON
  var pathEnv = opt.path || process.env.PATH || ''
  var pathExt = ['']

  pathEnv = pathEnv.split(colon)

  var pathExtExe = ''
  if (isWindows) {
    pathEnv.unshift(process.cwd())
    pathExtExe = (opt.pathExt || process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM')
    pathExt = pathExtExe.split(colon)

    // Always test the cmd itself first.  isexe will check to make sure
    // it's found in the pathExt set.
    if (cmd.indexOf('.') !== -1 && pathExt[0] !== '')
      pathExt.unshift('')
  }

  // If it has a slash, then we don't bother searching the pathenv.
  // just check the file itself, and that's it.
  if (cmd.match(/\//) || isWindows && cmd.match(/\\/))
    pathEnv = ['']

  return {
    env: pathEnv,
    ext: pathExt,
    extExe: pathExtExe
  }
}

function which (cmd, opt, cb) {
  if (typeof opt === 'function') {
    cb = opt
    opt = {}
  }

  var info = getPathInfo(cmd, opt)
  var pathEnv = info.env
  var pathExt = info.ext
  var pathExtExe = info.extExe
  var found = []

  ;(function F (i, l) {
    if (i === l) {
      if (opt.all && found.length)
        return cb(null, found)
      else
        return cb(getNotFoundError(cmd))
    }

    var pathPart = pathEnv[i]
    if (pathPart.charAt(0) === '"' && pathPart.slice(-1) === '"')
      pathPart = pathPart.slice(1, -1)

    var p = path.join(pathPart, cmd)
    if (!pathPart && (/^\.[\\\/]/).test(cmd)) {
      p = cmd.slice(0, 2) + p
    }
    ;(function E (ii, ll) {
      if (ii === ll) return F(i + 1, l)
      var ext = pathExt[ii]
      isexe(p + ext, { pathExt: pathExtExe }, function (er, is) {
        if (!er && is) {
          if (opt.all)
            found.push(p + ext)
          else
            return cb(null, p + ext)
        }
        return E(ii + 1, ll)
      })
    })(0, pathExt.length)
  })(0, pathEnv.length)
}

function whichSync (cmd, opt) {
  opt = opt || {}

  var info = getPathInfo(cmd, opt)
  var pathEnv = info.env
  var pathExt = info.ext
  var pathExtExe = info.extExe
  var found = []

  for (var i = 0, l = pathEnv.length; i < l; i ++) {
    var pathPart = pathEnv[i]
    if (pathPart.charAt(0) === '"' && pathPart.slice(-1) === '"')
      pathPart = pathPart.slice(1, -1)

    var p = path.join(pathPart, cmd)
    if (!pathPart && /^\.[\\\/]/.test(cmd)) {
      p = cmd.slice(0, 2) + p
    }
    for (var j = 0, ll = pathExt.length; j < ll; j ++) {
      var cur = p + pathExt[j]
      var is
      try {
        is = isexe.sync(cur, { pathExt: pathExtExe })
        if (is) {
          if (opt.all)
            found.push(cur)
          else
            return cur
        }
      } catch (ex) {}
    }
  }

  if (opt.all && found.length)
    return found

  if (opt.nothrow)
    return null

  throw getNotFoundError(cmd)
}


code:
# yallist

Yet Another Linked List

There are many doubly-linked list implementations like it, but this
one is mine.

For when an array would be too big, and a Map can't be iterated in
reverse order.

[![Build Status](https://travis-ci.org/isaacs/yallist.svg?branch=master)](https://travis-ci.org/isaacs/yallist) [![Coverage Status](https://coveralls.io/repos/isaacs/yallist/badge.svg?service=github)](https://coveralls.io/github/isaacs/yallist)

## basic usage

```javascript
var yallist = require('yallist')
var myList = yallist.create([1, 2, 3])
myList.push('foo')
myList.unshift('bar')
// of course pop() and shift() are there, too
console.log(myList.toArray()) // ['bar', 1, 2, 3, 'foo']
myList.forEach(function (k) {
  // walk the list head to tail
})
myList.forEachReverse(function (k, index, list) {
  // walk the list tail to head
})
var myDoubledList = myList.map(function (k) {
  return k + k
})
// now myDoubledList contains ['barbar', 2, 4, 6, 'foofoo']
// mapReverse is also a thing
var myDoubledListReverse = myList.mapReverse(function (k) {
  return k + k
}) // ['foofoo', 6, 4, 2, 'barbar']

var reduced = myList.reduce(function (set, entry) {
  set += entry
  return set
}, 'start')
console.log(reduced) // 'startfoo123bar'
```

## api

The whole API is considered "public".

Functions with the same name as an Array method work more or less the
same way.

There's reverse versions of most things because that's the point.

### Yallist

Default export, the class that holds and manages a list.

Call it with either a forEach-able (like an array) or a set of
arguments, to initialize the list.

The Array-ish methods all act like you'd expect.  No magic length,
though, so if you change that it won't automatically prune or add
empty spots.

### Yallist.create(..)

Alias for Yallist function.  Some people like factories.

#### yallist.head

The first node in the list

#### yallist.tail

The last node in the list

#### yallist.length

The number of nodes in the list.  (Change this at your peril.  It is
not magic like Array length.)

#### yallist.toArray()

Convert the list to an array.

#### yallist.forEach(fn, [thisp])

Call a function on each item in the list.

#### yallist.forEachReverse(fn, [thisp])

Call a function on each item in the list, in reverse order.

#### yallist.get(n)

Get the data at position `n` in the list.  If you use this a lot,
probably better off just using an Array.

#### yallist.getReverse(n)

Get the data at position `n`, counting from the tail.

#### yallist.map(fn, thisp)

Create a new Yallist with the result of calling the function on each
item.

#### yallist.mapReverse(fn, thisp)

Same as `map`, but in reverse.

#### yallist.pop()

Get the data from the list tail, and remove the tail from the list.

#### yallist.push(item, ...)

Insert one or more items to the tail of the list.

#### yallist.reduce(fn, initialValue)

Like Array.reduce.

#### yallist.reduceReverse

Like Array.reduce, but in reverse.

#### yallist.reverse

Reverse the list in place.

#### yallist.shift()

Get the data from the list head, and remove the head from the list.

#### yallist.slice([from], [to])

Just like Array.slice, but returns a new Yallist.

#### yallist.sliceReverse([from], [to])

Just like yallist.slice, but the result is returned in reverse.

#### yallist.toArray()

Create an array representation of the list.

#### yallist.toArrayReverse()

Create a reversed array representation of the list.

#### yallist.unshift(item, ...)

Insert one or more items to the head of the list.

#### yallist.unshiftNode(node)

Move a Node object to the front of the list.  (That is, pull it out of
wherever it lives, and make it the new head.)

If the node belongs to a different list, then that list will remove it
first.

#### yallist.pushNode(node)

Move a Node object to the end of the list.  (That is, pull it out of
wherever it lives, and make it the new tail.)

If the node belongs to a list already, then that list will remove it
first.

#### yallist.removeNode(node)

Remove a node from the list, preserving referential integrity of head
and tail and other nodes.

Will throw an error if you try to have a list remove a node that
doesn't belong to it.

### Yallist.Node

The class that holds the data and is actually the list.

Call with `var n = new Node(value, previousNode, nextNode)`

Note that if you do direct operations on Nodes themselves, it's very
easy to get into weird states where the list is broken.  Be careful :)

#### node.next

The next node in the list.

#### node.prev

The previous node in the list.

#### node.value

The data the node contains.

#### node.list

The list to which this node belongs.  (Null if it does not belong to
any list.)


code:
var Yallist = require('./yallist.js')

Yallist.prototype[Symbol.iterator] = function* () {
  for (let walker = this.head; walker; walker = walker.next) {
    yield walker.value
  }
}


yallist

description: Yet Another Linked List

test: test

test: tap test/*.js --100

postversion: npm publish

author: Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)


code:
module.exports = Yallist

Yallist.Node = Node
Yallist.create = Yallist

function Yallist (list) {
  var self = this
  if (!(self instanceof Yallist)) {
    self = new Yallist()
  }

  self.tail = null
  self.head = null
  self.length = 0

  if (list && typeof list.forEach === 'function') {
    list.forEach(function (item) {
      self.push(item)
    })
  } else if (arguments.length > 0) {
    for (var i = 0, l = arguments.length; i < l; i++) {
      self.push(arguments[i])
    }
  }

  return self
}

Yallist.prototype.removeNode = function (node) {
  if (node.list !== this) {
    throw new Error('removing node which does not belong to this list')
  }

  var next = node.next
  var prev = node.prev

  if (next) {
    next.prev = prev
  }

  if (prev) {
    prev.next = next
  }

  if (node === this.head) {
    this.head = next
  }
  if (node === this.tail) {
    this.tail = prev
  }

  node.list.length--
  node.next = null
  node.prev = null
  node.list = null
}

Yallist.prototype.unshiftNode = function (node) {
  if (node === this.head) {
    return
  }

  if (node.list) {
    node.list.removeNode(node)
  }

  var head = this.head
  node.list = this
  node.next = head
  if (head) {
    head.prev = node
  }

  this.head = node
  if (!this.tail) {
    this.tail = node
  }
  this.length++
}

Yallist.prototype.pushNode = function (node) {
  if (node === this.tail) {
    return
  }

  if (node.list) {
    node.list.removeNode(node)
  }

  var tail = this.tail
  node.list = this
  node.prev = tail
  if (tail) {
    tail.next = node
  }

  this.tail = node
  if (!this.head) {
    this.head = node
  }
  this.length++
}

Yallist.prototype.push = function () {
  for (var i = 0, l = arguments.length; i < l; i++) {
    push(this, arguments[i])
  }
  return this.length
}

Yallist.prototype.unshift = function () {
  for (var i = 0, l = arguments.length; i < l; i++) {
    unshift(this, arguments[i])
  }
  return this.length
}

Yallist.prototype.pop = function () {
  if (!this.tail) {
    return undefined
  }

  var res = this.tail.value
  this.tail = this.tail.prev
  if (this.tail) {
    this.tail.next = null
  } else {
    this.head = null
  }
  this.length--
  return res
}

Yallist.prototype.shift = function () {
  if (!this.head) {
    return undefined
  }

  var res = this.head.value
  this.head = this.head.next
  if (this.head) {
    this.head.prev = null
  } else {
    this.tail = null
  }
  this.length--
  return res
}

Yallist.prototype.forEach = function (fn, thisp) {
  thisp = thisp || this
  for (var walker = this.head, i = 0; walker !== null; i++) {
    fn.call(thisp, walker.value, i, this)
    walker = walker.next
  }
}

Yallist.prototype.forEachReverse = function (fn, thisp) {
  thisp = thisp || this
  for (var walker = this.tail, i = this.length - 1; walker !== null; i--) {
    fn.call(thisp, walker.value, i, this)
    walker = walker.prev
  }
}

Yallist.prototype.get = function (n) {
  for (var i = 0, walker = this.head; walker !== null && i < n; i++) {
    // abort out of the list early if we hit a cycle
    walker = walker.next
  }
  if (i === n && walker !== null) {
    return walker.value
  }
}

Yallist.prototype.getReverse = function (n) {
  for (var i = 0, walker = this.tail; walker !== null && i < n; i++) {
    // abort out of the list early if we hit a cycle
    walker = walker.prev
  }
  if (i === n && walker !== null) {
    return walker.value
  }
}

Yallist.prototype.map = function (fn, thisp) {
  thisp = thisp || this
  var res = new Yallist()
  for (var walker = this.head; walker !== null;) {
    res.push(fn.call(thisp, walker.value, this))
    walker = walker.next
  }
  return res
}

Yallist.prototype.mapReverse = function (fn, thisp) {
  thisp = thisp || this
  var res = new Yallist()
  for (var walker = this.tail; walker !== null;) {
    res.push(fn.call(thisp, walker.value, this))
    walker = walker.prev
  }
  return res
}

Yallist.prototype.reduce = function (fn, initial) {
  var acc
  var walker = this.head
  if (arguments.length > 1) {
    acc = initial
  } else if (this.head) {
    walker = this.head.next
    acc = this.head.value
  } else {
    throw new TypeError('Reduce of empty list with no initial value')
  }

  for (var i = 0; walker !== null; i++) {
    acc = fn(acc, walker.value, i)
    walker = walker.next
  }

  return acc
}

Yallist.prototype.reduceReverse = function (fn, initial) {
  var acc
  var walker = this.tail
  if (arguments.length > 1) {
    acc = initial
  } else if (this.tail) {
    walker = this.tail.prev
    acc = this.tail.value
  } else {
    throw new TypeError('Reduce of empty list with no initial value')
  }

  for (var i = this.length - 1; walker !== null; i--) {
    acc = fn(acc, walker.value, i)
    walker = walker.prev
  }

  return acc
}

Yallist.prototype.toArray = function () {
  var arr = new Array(this.length)
  for (var i = 0, walker = this.head; walker !== null; i++) {
    arr[i] = walker.value
    walker = walker.next
  }
  return arr
}

Yallist.prototype.toArrayReverse = function () {
  var arr = new Array(this.length)
  for (var i = 0, walker = this.tail; walker !== null; i++) {
    arr[i] = walker.value
    walker = walker.prev
  }
  return arr
}

Yallist.prototype.slice = function (from, to) {
  to = to || this.length
  if (to < 0) {
    to += this.length
  }
  from = from || 0
  if (from < 0) {
    from += this.length
  }
  var ret = new Yallist()
  if (to < from || to < 0) {
    return ret
  }
  if (from < 0) {
    from = 0
  }
  if (to > this.length) {
    to = this.length
  }
  for (var i = 0, walker = this.head; walker !== null && i < from; i++) {
    walker = walker.next
  }
  for (; walker !== null && i < to; i++, walker = walker.next) {
    ret.push(walker.value)
  }
  return ret
}

Yallist.prototype.sliceReverse = function (from, to) {
  to = to || this.length
  if (to < 0) {
    to += this.length
  }
  from = from || 0
  if (from < 0) {
    from += this.length
  }
  var ret = new Yallist()
  if (to < from || to < 0) {
    return ret
  }
  if (from < 0) {
    from = 0
  }
  if (to > this.length) {
    to = this.length
  }
  for (var i = this.length, walker = this.tail; walker !== null && i > to; i--) {
    walker = walker.prev
  }
  for (; walker !== null && i > from; i--, walker = walker.prev) {
    ret.push(walker.value)
  }
  return ret
}

Yallist.prototype.reverse = function () {
  var head = this.head
  var tail = this.tail
  for (var walker = head; walker !== null; walker = walker.prev) {
    var p = walker.prev
    walker.prev = walker.next
    walker.next = p
  }
  this.head = tail
  this.tail = head
  return this
}

function push (self, item) {
  self.tail = new Node(item, self.tail, null, self)
  if (!self.head) {
    self.head = self.tail
  }
  self.length++
}

function unshift (self, item) {
  self.head = new Node(item, null, self.head, self)
  if (!self.tail) {
    self.tail = self.head
  }
  self.length++
}

function Node (value, prev, next, list) {
  if (!(this instanceof Node)) {
    return new Node(value, prev, next, list)
  }

  this.list = list
  this.value = value

  if (prev) {
    prev.next = this
    this.prev = prev
  } else {
    this.prev = null
  }

  if (next) {
    next.prev = this
    this.next = next
  } else {
    this.next = null
  }
}


yorkie

description: githooks management forked from husky

test: jest

format: prettier --single-quote --no-semi --write **/*.js

install: node bin/install.js

uninstall: node bin/uninstall.js

keywords: git hook hooks pre-commit precommit post-commit postcommit pre-push prepush post-merge postmerge test

authors:
Typicode <typicode@gmail.com>
Evan You


code: applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-push pre-receive update post-receive post-update push-to-checkout pre-auto-gc post-rewrite sendemail-validate


code:
'use strict'

const fs = require('fs')
const path = require('path')
const findParent = require('./utils/find-parent')
const findHooksDir = require('./utils/find-hooks-dir')
const getHookScript = require('./utils/get-hook-script')
const is = require('./utils/is')
const hooks = require('./hooks.json')

const SKIP = 'SKIP'
const UPDATE = 'UPDATE'
const MIGRATE_GHOOKS = 'MIGRATE_GHOOKS'
const MIGRATE_PRE_COMMIT = 'MIGRATE_PRE_COMMIT'
const CREATE = 'CREATE'

function write(filename, data) {
  fs.writeFileSync(filename, data)
  fs.chmodSync(filename, parseInt('0755', 8))
}

function createHook(depDir, projectDir, hooksDir, hookName, runnerPath) {
  const filename = path.join(hooksDir, hookName)

  let packageDir
  // prioritize package.json next to .git
  // this avoids double-install in lerna monorepos where both root and sub
  // package depends on this module
  if (fs.existsSync(path.join(projectDir, 'package.json'))) {
    packageDir = projectDir
  } else {
    packageDir = findParent(depDir, 'package.json')
  }

  // In order to support projects with package.json in a different directory
  // than .git, find relative path from project directory to package.json
  const relativePath = path.join('.', path.relative(projectDir, packageDir))

  const hookScript = getHookScript(hookName, relativePath, runnerPath)

  // Create hooks directory if needed
  if (!fs.existsSync(hooksDir)) fs.mkdirSync(hooksDir)

  if (!fs.existsSync(filename)) {
    write(filename, hookScript)
    return CREATE
  }

  if (is.ghooks(filename)) {
    write(filename, hookScript)
    return MIGRATE_GHOOKS
  }

  if (is.preCommit(filename)) {
    write(filename, hookScript)
    return MIGRATE_PRE_COMMIT
  }

  if (is.huskyOrYorkie(filename)) {
    write(filename, hookScript)
    return UPDATE
  }

  return SKIP
}

function installFrom(depDir) {
  try {
    const isInSubNodeModule = (depDir.match(/node_modules/g) || []).length > 1
    if (isInSubNodeModule) {
      return console.log(
        "trying to install from sub 'node_module' directory,",
        'skipping Git hooks installation'
      )
    }

    const projectDir = findParent(depDir, 'package.json')
    const hooksDir = findHooksDir(projectDir)
    const runnerPath = './node_modules/yorkie/src/runner.js'

    if (hooksDir) {
      hooks
        .map(function(hookName) {
          return {
            hookName: hookName,
            action: createHook(depDir, projectDir, hooksDir, hookName, runnerPath)
          }
        })
        .forEach(function(item) {
          switch (item.action) {
            case MIGRATE_GHOOKS:
              console.log(`migrating existing ghooks ${item.hookName} script`)
              break
            case MIGRATE_PRE_COMMIT:
              console.log(
                `migrating existing pre-commit ${item.hookName} script`
              )
              break
            case UPDATE:
              break
            case SKIP:
              console.log(`skipping ${item.hookName} hook (existing user hook)`)
              break
            case CREATE:
              break
            default:
              console.error('Unknown action')
          }
        })
      console.log('done\n')
    } else {
      console.log("can't find .git directory, skipping Git hooks installation")
    }
  } catch (e) {
    console.error(e)
  }
}

module.exports = installFrom


code:
const fs = require('fs')
const path = require('path')
const execa = require('execa')

const cwd = process.cwd()
const pkg = fs.readFileSync(path.join(cwd, 'package.json'))
const hooks = JSON.parse(pkg).gitHooks
if (!hooks) {
  process.exit(0)
}

const hook = process.argv[2]
const command = hooks[hook]
if (!command) {
  process.exit(0)
}

console.log(` > running ${hook} hook: ${command}`)
try {
  execa.shellSync(command, { stdio: 'inherit' })
} catch (e) {
  process.exit(1)
}


code:
'use strict'

const fs = require('fs')
const hooks = require('./hooks.json')
const findParent = require('./utils/find-parent')
const findHooksDir = require('./utils/find-hooks-dir')
const is = require('./utils/is')

function removeHook(dir, name) {
  const filename = `${dir}/${name}`

  if (fs.existsSync(filename) && is.huskyOrYorkie(filename)) {
    fs.unlinkSync(`${dir}/${name}`)
  }
}

function uninstallFrom(huskyDir) {
  try {
    const hooksDir = findHooksDir(findParent(huskyDir, '.git'))

    hooks.forEach(function(hookName) {
      removeHook(hooksDir, hookName)
    })
    console.log('done\n')
  } catch (e) {
    console.error(e)
  }
}

module.exports = uninstallFrom


code:
'use strict'

const fs = require('fs')
const path = require('path')
const findParent = require('./find-parent')

function findHooksDir(dir) {
  if (dir) {
    let gitDir = path.join(dir, '.git')
    if (!fs.existsSync(gitDir)) {
      return
    }

    const stats = fs.lstatSync(gitDir)

    if (stats.isFile()) {
      // Expect following format
      // git: pathToGit
      // On Windows pathToGit can contain ':' (example "gitdir: C:/Some/Path")
      const gitFileData = fs.readFileSync(gitDir, 'utf-8')
      gitDir = gitFileData
        .split(':')
        .slice(1)
        .join(':')
        .trim()
    }

    return path.resolve(dir, gitDir, 'hooks')
  }
}

module.exports = findHooksDir


code:
'use strict'

const fs = require('fs')
const path = require('path')

module.exports = function findParent(currentDir, name) {
  const dirs = currentDir.split(path.sep)

  while (dirs.pop()) {
    const dir = dirs.join(path.sep)

    if (fs.existsSync(path.join(dir, name))) {
      return path.resolve(dir)
    }
  }
}


code:
'use strict'

const normalize = require('normalize-path')
const stripIndent = require('strip-indent')
const pkg = require('../../package.json')

function platformSpecific() {
  // On OS X and Linux, try to use nvm if it's installed
  if (process.platform === 'win32') {
    // Add
    // Node standard installation path /c/Program Files/nodejs
    // for GUI apps
    // https://github.com/typicode/yorkie/issues/49
    return stripIndent(
      `
      # Node standard installation
      export PATH="$PATH:/c/Program Files/nodejs"`
    )
  } else {
    // Using normalize to support ' in path
    // https://github.com/typicode/yorkie/issues/117
    const home = normalize(process.env.HOME)

    return stripIndent(
      `
        # Add common path where Node can be found
        # Brew standard installation path /usr/local/bin
        # Node standard installation path /usr/local
        export PATH="$PATH:/usr/local/bin:/usr/local"

        # Try to load nvm using path of standard installation
        load_nvm ${home}/.nvm
        run_nvm`
    )

    return arr.join('\n')
  }
}

module.exports = function getHookScript(hookName, relativePath, runnerPath) {
  // On Windows normalize path (i.e. convert \ to /)
  const normalizedPath = normalize(relativePath)

  const noVerifyMessage =
    hookName === 'prepare-commit-msg'
      ? '(cannot be bypassed with --no-verify due to Git specs)'
      : '(add --no-verify to bypass)'

  return [
    stripIndent(
      `
      #!/bin/sh
      #yorkie ${pkg.version}

      command_exists () {
        command -v "$1" >/dev/null 2>&1
      }

      has_hook_script () {
        [ -f package.json ] && cat package.json | grep -q "\\"$1\\"[[:space:]]*:"
      }

      # OS X and Linux only
      load_nvm () {
        # If nvm is not loaded, load it
        command_exists nvm || {
          export NVM_DIR="$1"
          [ -s "$1/nvm.sh" ] && . "$1/nvm.sh"
        }
      }

      # OS X and Linux only
      run_nvm () {
        # If nvm has been loaded correctly, use project .nvmrc
        command_exists nvm && [ -f .nvmrc ] && nvm use
      }

      cd "${normalizedPath}"

      # Check if ${hookName} is defined, skip if not
      has_hook_script ${hookName} || exit 0`
    ).trim(),

    platformSpecific(),

    stripIndent(
      `
      # Export Git hook params
      export GIT_PARAMS="$*"

      # Run hook
      node "${runnerPath}" ${hookName} || {
        echo
        echo "${hookName} hook failed ${noVerifyMessage}"
        exit 1
      }
      `
    )
  ].join('\n')
}


code:
'use strict'

const fs = require('fs')

function readFile(filename) {
  return fs.readFileSync(filename, 'utf-8')
}

function huskyOrYorkie(filename) {
  const data = readFile(filename)
  return data.indexOf('#husky') !== -1 || data.indexOf('#yorkie') !== -1
}

function ghooks(filename) {
  const data = readFile(filename)
  return data.indexOf('// Generated by ghooks. Do not edit this file.') !== -1
}

function preCommit(filename) {
  const data = readFile(filename)
  return data.indexOf('./node_modules/pre-commit/hook') !== -1
}

module.exports = {
  huskyOrYorkie,
  ghooks,
  preCommit
}


code:
# zip-lib
zip and unzip library for node.

[![npm Package](https://img.shields.io/npm/v/zip-lib.svg)](https://www.npmjs.org/package/zip-lib) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/fpsqdb/zip-lib/blob/master/LICENSE) ![node](https://img.shields.io/node/v/zip-lib) ![Node.js CI](https://github.com/fpsqdb/zip-lib/workflows/Node.js%20CI/badge.svg)

## Install

```
npm install zip-lib
```

## Quick Start

* [Zip](#Zip)
    - [Zip single file](#zip-single-file)
    - [Zip single folder](#zip-single-folder)
* [Unzip](#unzip)
* [Advanced usage](#advance-usage)
    - [Zip multiple files and folders](#zip-multiple-files-and-folders)
    - [Zip with metadata](#zip-with-metadata)
    - [Unzip with entry callback](#unzip-with-entry-callback)
    - [Unzip and exclude specified entries](#unzip-and-exclude-specified-entries)
    - [Cancel zip](#cancel-zip)
    - [Cancel unzip](#cancel-unzip)
* [API](#api)
    - Method: [archiveFile](#archivefile)
    - Method: [archiveFolder](#archivefolder)
    - Method: [extract](#extract)
    - Class: [Zip](#class-zip)
    - Class: [Unzip](#class-unzip)
    - Options: [IZipOptions](#izipoptions)
    - Options: [IExtractOptions](#iextractoptions)

## Zip
You can use **zip-lib** to compress files or folders.

### Zip single file

```js
const zl = require("zip-lib");

zl.archiveFile("path/to/file.txt", "path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

### Zip single folder

```js
const zl = require("zip-lib");

zl.archiveFolder("path/to/folder", "path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

## Unzip

```js
const zl = require("zip-lib");

zl.extract("path/to/target.zip", "path/to/target").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

## Advanced usage

### Zip multiple files and folders

```js
const zl = require("zip-lib");

const zip = new zl.Zip();
// Adds a file from the file system
zip.addFile("path/to/file.txt");
// Adds a folder from the file system, putting its contents at the root of archive
zip.addFolder("path/to/folder");
// Generate zip file.
zip.archive("path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

The `path/to/folder` directory is as follows:

```
path/to/folder
.
├── dir1
│   ├── file.ext
├── dir2
└── file_in_root.ext
```

And the generated `path/to/target.zip` archive file directory will be as follows:

```
path/to/target.zip
.
├── file.txt
├── dir1
│   ├── file.ext
├── dir2
└── file_in_root.ext
```

### Zip with metadata

```js
const zl = require("zip-lib");

const zip = new zl.Zip();
// Adds a file from the file system
zip.addFile("path/to/file.txt", "renamedFile.txt");
zip.addFile("path/to/file2.txt", "folder/file.txt");
// Adds a folder from the file system, and naming it `new folder` within the archive
zip.addFolder("path/to/folder", "new folder");
// Generate zip file.
zip.archive("path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

The `path/to/folder` directory is as follows:

```
path/to/folder
.
├── dir1
│   ├── file.ext
├── dir2
└── file_in_root.ext
```

And the generated `path/to/target.zip` archive file directory will be as follows:

```
path/to/target.zip
.
├── renamedFile.txt
├── folder
│   ├── file.txt
│── new folder
    ├── dir1
    │   ├── file.ext
    ├── dir2
    └── file_in_root.ext
```

### Unzip with entry callback
Using `onEntry` callback we can know the current progress of extracting and control the extraction operation. See [IExtractOptions](#iextractoptions).

```js
const zl = require("zip-lib");

const unzip = new zl.Unzip({
    // Called before an item is extracted.
    onEntry: function (event) {
        console.log(event.entryCount, event.entryName);
    }
})
unzip.extract("path/to/target.zip", "path/to/target").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

### Unzip and exclude specified entries
The following code shows how to exclude the `__MACOSX` folder in the zip file when extracting. See [IExtractOptions](#iextractoptions).

```js
const zl = require("zip-lib");

const unzip = new zl.Unzip({
    // Called before an item is extracted.
    onEntry: function (event) {
        if (/^__MACOSX\//.test(event.entryName)) {
            // entry name starts with __MACOSX/
            event.preventDefault();
        }
    }
})
unzip.extract("path/to/target.zip", "path/to/target").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});
```

### Cancel zip
If the `cancel` method is called after the archive is complete, nothing will happen.

```js
const zl = require("zip-lib");

const zip = new zl.Zip();
zip.addFile("path/to/file.txt");
zip.archive("path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    if (err.name === "Canceled") {
        console.log("cancel");
    } else {
        console.log(err);
    }
});

// Cancel zip
zip.cancel();
```

### Cancel unzip
If the `cancel` method is called after the extract is complete, nothing will happen.

```js
const zl = require("zip-lib");

const unzip = new zl.Unzip();
unzip.extract("path/to/target.zip", "path/to/target").then(function () {
    console.log("done");
}, function (err) {
    if (err.name === "Canceled") {
        console.log("cancel");
    } else {
        console.log(err);
    }
});

// cancel
unzip.cancel();
```

## API

### Method: archiveFile

**archiveFile(file, zipFile, [options])**

Compress a single file to zip.

- `file`: String
- `zipFile`: String
- `options?`: [IZipOptions](#izipoptions) (optional)

Returns: `Promise<viod>`

### Method: archiveFolder

**archiveFolder(folder, zipFile, [options])**

Compress all the contents of the specified folder to zip.

- `folder`: String
- `zipFile`: String
- `options?`: [IZipOptions](#izipoptions) (optional)

Returns: `Promise<void>`

### Method: extract

**extract(zipFile, targetFolder, [options])**

Extract the zip file to the specified location.

- `zipFile`: String
- `targetFolder`: String
- `options?`: [IExtractOptions](#iextractoptions) (optional)

Returns: `Promise<void>`

### Class: Zip
Compress files or folders to a zip file.

**Constructor: new Zip([options])**

- `options?`: [IZipOptions](#izipoptions)

**Method: addFile(file, [metadataPath])**

Adds a file from the file system at realPath into the zipfile as metadataPath.

- `file`: String
- `metadataPath?`: String (optional) - Typically metadataPath would be calculated as path.relative(root, realPath). A valid metadataPath must not start with `/` or `/[A-Za-z]:\//`, and must not contain `..`.

Returns: `void`

**Method: addFolder(folder, [metadataPath])**

Adds a folder from the file system at realPath into the zipfile as metadataPath.

- `folder`: String
- `metadataPath?`: String (optional) - Typically metadataPath would be calculated as path.relative(root, realPath). A valid metadataPath must not start with `/` or `/[A-Za-z]:\//`, and must not contain `..`.

Returns: `void`

**Method: archive(zipFile)**

Generate zip file.

- `zipFile`: String

Returns: `Promise<viod>`

**Method: cancel()**

Cancel compression. If the `cancel` method is called after the archive is complete, nothing will happen.

Returns: `void`

### Class: Unzip
Extract the zip file.

**Constructor: new Unzip([options])**

- `options?`: [IZipOptions](#izipoptions) (optional)

**Method: extract(zipFile, targetFolder)**

Extract the zip file to the specified location.

- `zipFile`: String
- `targetFolder`: String

Returns: `Promise<void>`

**Method: cancel()**

If the `cancel` method is called after the extract is complete, nothing will happen.

Returns: `void`

### Options: IZipOptions

Object
- `followSymlinks?`: Boolean (optional) - Indicates how to handle when the given path is a symbolic link. The default value is `false`.
`true`: add the target of the symbolic link to the zip.
`false`: add symbolic link itself to the zip.

### Options: IExtractOptions

Object
- `overwrite?`: String (optional) - If it is true, the target directory will be deleted before extract. The default value is `false`.
- `symlinkAsFileOnWindows?`: Boolean (optional) - Extract symbolic links as files on Windows. This value is only available on Windows and ignored on other platforms. The default value is `true`.
If `true`, the symlink in the zip will be extracted as a normal file on Windows.
If `false`, the symlink in the zip will be extracted as a symlink correctly on Windows, but an `EPERM` error will be thrown under non-administrators.

    > ⚠**WARNING:** On Windows, the default security policy allows only administrators to create symbolic links. If you set `symlinkAsFileOnWindows` to `false` and the zip contains symlink, be sure to run the code under the administrator, otherwise an `EPERM` error will be thrown.

- `onEntry?`: Function (optional) - Called before an item is extracted.
Arguments:
    - `event`: Object - Represents an event that an entry is about to be extracted.
        - `entryName`: String (readonly) - Entry name.
        - `entryCount`: Number (readonly) - Total number of entries.
        - `preventDefault()`: Function - Prevent extracting current entry. This method can be used to prevent extraction of the current item. By calling this method we can control which items can be extracted.

# License
Licensed under the [MIT](https://github.com/fpsqdb/zip-lib/blob/master/LICENSE) license.


code:
export interface ICancelable {
    /**
     * Cancel operation
     */
    cancel(): void;
}
export declare class CancellationToken {
    private _isCancelled;
    private _callbacks;
    /**
     * A flag signalling is cancellation has been requested.
     */
    get isCancelled(): boolean;
    /**
     * Subscribe a callback when cancellation is requested. The callback
     * only ever fires `once` as cancellation can only happen once.
     * @param cb A function will be called when cancellation is requested.
     * @returns A function that Unsubscribe the cancellation callback.
     */
    onCancelled(cb: () => void): () => void;
    cancel(): void;
}
export declare abstract class Cancelable implements ICancelable {
    abstract cancel(): void;
    /**
     * Ignore any other error if the `cancel` method has been called
     *
     * Error: EBADF: bad file descriptor, read
     * EBADF error may occur when calling the cancel method.
     * see https://travis-ci.org/fpsqdb/zip-lib/jobs/606040627#L124
     * @param error
     */
    protected wrapError(error: Error, isCanceled: boolean): Error;
    /**
     * Returns an error that signals cancellation.
     */
    protected canceledError(): Error;
}


code:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Cancelable = exports.CancellationToken = void 0;
class CancellationToken {
    constructor() {
        this._isCancelled = false;
        this._callbacks = new Set();
    }
    /**
     * A flag signalling is cancellation has been requested.
     */
    get isCancelled() {
        return this._isCancelled;
    }
    /**
     * Subscribe a callback when cancellation is requested. The callback
     * only ever fires `once` as cancellation can only happen once.
     * @param cb A function will be called when cancellation is requested.
     * @returns A function that Unsubscribe the cancellation callback.
     */
    onCancelled(cb) {
        if (this.isCancelled) {
            cb();
            return () => {
                // noop
            };
        }
        this._callbacks.add(cb);
        return () => this._callbacks.delete(cb);
    }
    cancel() {
        if (this._isCancelled) {
            return;
        }
        this._isCancelled = true;
        this._callbacks.forEach((cb) => cb());
        this._callbacks.clear();
    }
}
exports.CancellationToken = CancellationToken;
class Cancelable {
    /**
     * Ignore any other error if the `cancel` method has been called
     *
     * Error: EBADF: bad file descriptor, read
     * EBADF error may occur when calling the cancel method.
     * see https://travis-ci.org/fpsqdb/zip-lib/jobs/606040627#L124
     * @param error
     */
    wrapError(error, isCanceled) {
        if (isCanceled) {
            return this.canceledError();
        }
        return error;
    }
    /**
     * Returns an error that signals cancellation.
     */
    canceledError() {
        const error = new Error("Canceled");
        error.name = error.message;
        return error;
    }
}
exports.Cancelable = Cancelable;


code:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isRootPath = exports.rimraf = exports.pathExists = exports.ensureFolder = exports.getFileEntry = exports.readdirp = void 0;
const path = require("path");
const util = require("./util");
async function readdirp(folder) {
    const result = [];
    const files = await util.readdir(folder);
    for (const item of files) {
        const file = path.join(folder, item);
        const entry = await getFileEntry(file);
        if (!entry.isSymbolicLink && entry.type === "dir") {
            const subFiles = await readdirp(file);
            if (subFiles.length > 0) {
                result.push(...subFiles);
                // If the folder is not empty, don't need to add the folder itself.
                // continue and skip the code below
                continue;
            }
        }
        result.push(entry);
    }
    return result;
}
exports.readdirp = readdirp;
async function getFileEntry(target) {
    const stat = await util.lstat(target);
    let isSymbolicLink = false;
    let fileType = "file";
    if (stat.isDirectory()) {
        fileType = "dir";
    }
    else {
        if (stat.isSymbolicLink()) {
            isSymbolicLink = true;
            // If the path is a link, we must instead use fs.stat() to find out if the
            // link is a directory or not because lstat will always return the stat of
            // the link which is always a file.
            const actualStat = await util.stat(target);
            if (actualStat.isDirectory()) {
                fileType = "dir";
            }
        }
    }
    return {
        path: target,
        isSymbolicLink,
        type: fileType,
        mtime: stat.mtime,
        mode: stat.mode
    };
}
exports.getFileEntry = getFileEntry;
async function ensureFolder(folder) {
    // stop at root
    if (folder === path.dirname(folder)) {
        return Promise.resolve();
    }
    try {
        await mkdir(folder);
    }
    catch (error) {
        // ENOENT: a parent folder does not exist yet, continue
        // to create the parent folder and then try again.
        if (error.code === "ENOENT") {
            await ensureFolder(path.dirname(folder));
            return mkdir(folder);
        }
        // Any other error
        return Promise.reject(error);
    }
}
exports.ensureFolder = ensureFolder;
async function pathExists(target) {
    try {
        await util.access(target);
        return true;
    }
    catch (error) {
        return false;
    }
}
exports.pathExists = pathExists;
async function rimraf(target) {
    if (isRootPath(target)) {
        // refuse to recursively delete root
        return Promise.reject(new Error(`Refuse to recursively delete root, path: "${target}"`));
    }
    try {
        const stat = await util.lstat(target);
        // Folder delete (recursive) - NOT for symbolic links though!
        if (stat.isDirectory() && !stat.isSymbolicLink()) {
            // Children
            const children = await util.readdir(target);
            await Promise.all(children.map(child => rimraf(path.join(target, child))));
            // Folder
            await util.rmdir(target);
        }
        // Single file delete
        else {
            // chmod as needed to allow for unlink
            const mode = stat.mode;
            if (!(mode & 128)) { // 128 === 0200
                await util.chmod(target, mode | 128);
            }
            return util.unlink(target);
        }
    }
    catch (error) {
        if (error.code !== "ENOENT") {
            throw error;
        }
    }
}
exports.rimraf = rimraf;
async function mkdir(folder) {
    try {
        await util.mkdir(folder, 0o777);
    }
    catch (error) {
        // ENOENT: a parent folder does not exist yet or folder name is invalid.
        if (error.code === "ENOENT") {
            return Promise.reject(error);
        }
        // Any other error: check if folder exists and
        // return normally in that case if its a folder
        try {
            const fileStat = await util.stat(folder);
            if (!fileStat.isDirectory()) {
                return Promise.reject(new Error(`"${folder}" exists and is not a directory.`));
            }
        }
        catch (statError) {
            throw error; // rethrow original error
        }
    }
}
// "A"
const charA = 65;
// "Z"
const charZ = 90;
// "a"
const chara = 97;
// "z"
const charz = 122;
// ":"
const charColon = 58;
// "\"
const charWinSep = 92;
// "/"
const cahrUnixSep = 47;
function isDriveLetter(char0) {
    return char0 >= charA && char0 <= charZ || char0 >= chara && char0 <= charz;
}
const winSep = "\\";
const unixSep = "/";
function isRootPath(target) {
    if (!target) {
        return false;
    }
    if (target === winSep ||
        target === unixSep) {
        return true;
    }
    if (process.platform === "win32") {
        if (target.length > 3) {
            return false;
        }
        return isDriveLetter(target.charCodeAt(0))
            && target.charCodeAt(1) === charColon
            && (target.length === 2 || target.charCodeAt(2) === charWinSep || target.charCodeAt(2) === cahrUnixSep);
    }
    return false;
}
exports.isRootPath = isRootPath;


code:
import { IZipOptions } from "./zip";
import { IExtractOptions } from "./unzip";
export * from "./zip";
export * from "./unzip";
/**
 * Compress a single file to zip.
 * @param file
 * @param zipFile the zip file path.
 * @param options
 */
export declare function archiveFile(file: string, zipFile: string, options?: IZipOptions): Promise<void>;
/**
 * Compress all the contents of the specified folder to zip.
 * @param folder
 * @param zipFile the zip file path.
 * @param options
 */
export declare function archiveFolder(folder: string, zipFile: string, options?: IZipOptions): Promise<void>;
/**
 * Extract the zip file to the specified location.
 * @param zipFile
 * @param targetFolder
 * @param options
 */
export declare function extract(zipFile: string, targetFolder: string, options?: IExtractOptions): Promise<void>;


code:
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.extract = exports.archiveFolder = exports.archiveFile = void 0;
const zip_1 = require("./zip");
const unzip_1 = require("./unzip");
__exportStar(require("./zip"), exports);
__exportStar(require("./unzip"), exports);
/**
 * Compress a single file to zip.
 * @param file
 * @param zipFile the zip file path.
 * @param options
 */
function archiveFile(file, zipFile, options) {
    const zip = new zip_1.Zip(options);
    zip.addFile(file);
    return zip.archive(zipFile);
}
exports.archiveFile = archiveFile;
/**
 * Compress all the contents of the specified folder to zip.
 * @param folder
 * @param zipFile the zip file path.
 * @param options
 */
function archiveFolder(folder, zipFile, options) {
    const zip = new zip_1.Zip(options);
    zip.addFolder(folder);
    return zip.archive(zipFile);
}
exports.archiveFolder = archiveFolder;
/**
 * Extract the zip file to the specified location.
 * @param zipFile
 * @param targetFolder
 * @param options
 */
function extract(zipFile, targetFolder, options) {
    const unzip = new unzip_1.Unzip(options);
    return unzip.extract(zipFile, targetFolder);
}
exports.extract = extract;


code:
import { Cancelable } from "./cancelable";
export interface IExtractOptions {
    /**
     * If it is `true`, the target directory will be deleted before extract.
     * The default value is `false`.
     */
    overwrite?: boolean;
    /**
     * Extract symbolic links as files on Windows. This value is only available on Windows and ignored on other platforms.
     * The default value is `true`.
     *
     * If `true`, the symlink in the zip will be extracted as a normal file on Windows.
     *
     * If `false`, the symlink in the zip will be extracted as a symlink correctly on Windows, but an `EPERM` error will be thrown under non-administrators.
     *
     * > ⚠**WARNING:** On Windows, the default security policy allows only administrators to create symbolic links.
     * If you set `symlinkAsFileOnWindows` to `false` and the zip contains symlink,
     * be sure to run the code under the administrator, otherwise an `EPERM` error will be thrown.
     */
    symlinkAsFileOnWindows?: boolean;
    /**
     * Called before an item is extracted.
     * @param event
     */
    onEntry?: (event: IEntryEvent) => void;
}
/**
 * The IEntryEvent interface represents an event that an entry is about to be extracted.
 */
export interface IEntryEvent {
    /**
     * Entry name.
     */
    readonly entryName: string;
    /**
     * Total number of entries.
     */
    readonly entryCount: number;
    /**
     * Prevent extracting current entry.
     */
    preventDefault(): void;
}
/**
 * Extract the zip file.
 */
export declare class Unzip extends Cancelable {
    private options?;
    /**
     *
     */
    constructor(options?: IExtractOptions | undefined);
    private zipFile;
    private token;
    /**
     * Extract the zip file to the specified location.
     * @param zipFile
     * @param targetFolder
     * @param options
     */
    extract(zipFile: string, targetFolder: string): Promise<void>;
    /**
     * Cancel decompression.
     * If the cancel method is called after the extract is complete, nothing will happen.
     */
    cancel(): void;
    private closeZip;
    private openZip;
    private handleEntry;
    private openZipFileStream;
    private extractEntry;
    private writeEntryToFile;
    private modeFromEntry;
    private createSymlink;
    private isOverwrite;
    private onEntryCallback;
    private symlinkToFile;
}


code:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Unzip = void 0;
const yauzl = require("yauzl");
const exfs = require("./fs");
const fs_1 = require("fs");
const path = require("path");
const util = require("./util");
const cancelable_1 = require("./cancelable");
class EntryEvent {
    /**
     *
     */
    constructor(_entryCount) {
        this._entryCount = _entryCount;
        this._isPrevented = false;
    }
    get entryName() {
        return this._entryName;
    }
    set entryName(name) {
        this._entryName = name;
    }
    get entryCount() {
        return this._entryCount;
    }
    get isPrevented() {
        return this._isPrevented;
    }
    preventDefault() {
        this._isPrevented = true;
    }
    reset() {
        this._isPrevented = false;
    }
}
class EntryContext {
    constructor(_targetFolder, _realTargetFolder, symlinkAsFileOnWindows) {
        this._targetFolder = _targetFolder;
        this._realTargetFolder = _realTargetFolder;
        this.symlinkAsFileOnWindows = symlinkAsFileOnWindows;
        this._symlinkFileNames = [];
    }
    get decodeEntryFileName() {
        return this._decodeEntryFileName;
    }
    set decodeEntryFileName(name) {
        this._decodeEntryFileName = name;
    }
    get targetFolder() {
        return this._targetFolder;
    }
    get realTargetFolder() {
        return this._realTargetFolder;
    }
    get symlinkFileNames() {
        return this._symlinkFileNames;
    }
    getFilePath() {
        return path.join(this.targetFolder, this.decodeEntryFileName);
    }
    async isOutsideTargetFolder(tpath) {
        if (this.symlinkFileNames.length === 0) {
            return false;
        }
        if (process.platform === "win32" &&
            this.symlinkAsFileOnWindows) {
            return false;
        }
        for (const fileName of this.symlinkFileNames) {
            if (tpath.includes(fileName)) {
                const realFilePath = await util.realpath(tpath);
                if (realFilePath.indexOf(this.realTargetFolder) !== 0) {
                    return true;
                }
            }
        }
        return false;
    }
}
/**
 * Extract the zip file.
 */
class Unzip extends cancelable_1.Cancelable {
    /**
     *
     */
    constructor(options) {
        super();
        this.options = options;
    }
    /**
     * Extract the zip file to the specified location.
     * @param zipFile
     * @param targetFolder
     * @param options
     */
    async extract(zipFile, targetFolder) {
        let extractedEntriesCount = 0;
        const token = new cancelable_1.CancellationToken();
        this.token = token;
        if (this.isOverwrite()) {
            await exfs.rimraf(targetFolder);
        }
        if (token.isCancelled) {
            return Promise.reject(this.canceledError());
        }
        await exfs.ensureFolder(targetFolder);
        const realTargetFolder = await util.realpath(targetFolder);
        const zfile = await this.openZip(zipFile, token);
        this.zipFile = zfile;
        zfile.readEntry();
        return new Promise((c, e) => {
            let anyError = null;
            const total = zfile.entryCount;
            zfile.once("error", (err) => {
                this.closeZip();
                e(this.wrapError(err, token.isCancelled));
            });
            zfile.once("close", () => {
                this.zipFile = null;
                if (anyError) {
                    e(this.wrapError(anyError, token.isCancelled));
                }
                else {
                    if (token.isCancelled) {
                        e(this.canceledError());
                    }
                    // If the zip content is empty, it will not receive the `zfile.on("entry")` event.
                    else if (total === 0) {
                        c(void 0);
                    }
                }
            });
            // Because openZip is an asynchronous method, openZip may not be completed when calling cancel,
            // so we need to check if it has been canceled after the openZip method returns.
            if (token.isCancelled) {
                this.closeZip();
                return;
            }
            const entryContext = new EntryContext(targetFolder, realTargetFolder, this.symlinkToFile());
            const entryEvent = new EntryEvent(total);
            zfile.on("entry", async (entry) => {
                // use UTF-8 in all situations
                // see https://github.com/thejoshwolfe/yauzl/issues/84
                const rawName = entry.fileName.toString("utf8");
                // allow backslash
                const fileName = rawName.replace(/\\/g, "/");
                // Because `decodeStrings` is `false`, we need to manually verify the entryname
                // see https://github.com/thejoshwolfe/yauzl#validatefilenamefilename
                const errorMessage = yauzl.validateFileName(fileName);
                if (errorMessage != null) {
                    anyError = new Error(errorMessage);
                    this.closeZip();
                    e(anyError);
                    return;
                }
                entryEvent.entryName = fileName;
                this.onEntryCallback(entryEvent);
                entryContext.decodeEntryFileName = fileName;
                try {
                    if (entryEvent.isPrevented) {
                        entryEvent.reset();
                        zfile.readEntry();
                    }
                    else {
                        await this.handleEntry(zfile, entry, entryContext, token);
                    }
                    extractedEntriesCount++;
                    if (extractedEntriesCount === total) {
                        c();
                    }
                }
                catch (error) {
                    anyError = this.wrapError(error, token.isCancelled);
                    this.closeZip();
                    e(anyError);
                }
            });
        });
    }
    /**
     * Cancel decompression.
     * If the cancel method is called after the extract is complete, nothing will happen.
     */
    cancel() {
        if (this.token) {
            this.token.cancel();
            this.token = null;
        }
        this.closeZip();
    }
    closeZip() {
        if (this.zipFile) {
            this.zipFile.close();
            this.zipFile = null;
        }
    }
    openZip(zipFile, token) {
        return new Promise((c, e) => {
            yauzl.open(zipFile, {
                lazyEntries: true,
                // see https://github.com/thejoshwolfe/yauzl/issues/84
                decodeStrings: false
            }, (err, zfile) => {
                if (err) {
                    e(this.wrapError(err, token.isCancelled));
                }
                else {
                    c(zfile);
                }
            });
        });
    }
    async handleEntry(zfile, entry, entryContext, token) {
        if (/\/$/.test(entryContext.decodeEntryFileName)) {
            // Directory file names end with '/'.
            // Note that entires for directories themselves are optional.
            // An entry's fileName implicitly requires its parent directories to exist.
            await exfs.ensureFolder(entryContext.getFilePath());
            zfile.readEntry();
        }
        else {
            // file entry
            await this.extractEntry(zfile, entry, entryContext, token);
        }
    }
    openZipFileStream(zfile, entry, token) {
        return new Promise((c, e) => {
            zfile.openReadStream(entry, (err, readStream) => {
                if (err) {
                    e(this.wrapError(err, token.isCancelled));
                }
                else {
                    c(readStream);
                }
            });
        });
    }
    async extractEntry(zfile, entry, entryContext, token) {
        const filePath = entryContext.getFilePath();
        const fileDir = path.dirname(filePath);
        await exfs.ensureFolder(fileDir);
        const outside = await entryContext.isOutsideTargetFolder(fileDir);
        if (outside) {
            const error = new Error(`Refuse to write file outside "${entryContext.targetFolder}", file: "${filePath}"`);
            error.name = "AFWRITE";
            return Promise.reject(error);
        }
        const readStream = await this.openZipFileStream(zfile, entry, token);
        await this.writeEntryToFile(readStream, entry, entryContext, token);
        zfile.readEntry();
    }
    async writeEntryToFile(readStream, entry, entryContext, token) {
        let fileStream;
        token.onCancelled(() => {
            if (fileStream) {
                readStream.unpipe(fileStream);
                fileStream.destroy(this.canceledError());
            }
        });
        return new Promise(async (c, e) => {
            try {
                const filePath = entryContext.getFilePath();
                const mode = this.modeFromEntry(entry);
                // see https://unix.stackexchange.com/questions/193465/what-file-mode-is-a-symlink
                const isSymlink = ((mode & 0o170000) === 0o120000);
                readStream.once("error", (err) => {
                    e(this.wrapError(err, token.isCancelled));
                });
                if (isSymlink) {
                    entryContext.symlinkFileNames.push(entryContext.decodeEntryFileName);
                }
                if (isSymlink && !this.symlinkToFile()) {
                    let linkContent = "";
                    readStream.on("data", (chunk) => {
                        if (chunk instanceof String) {
                            linkContent += chunk;
                        }
                        else {
                            linkContent += chunk.toString();
                        }
                    });
                    readStream.once("end", () => {
                        this.createSymlink(linkContent, filePath).then(c, e);
                    });
                }
                else {
                    fileStream = (0, fs_1.createWriteStream)(filePath, { mode });
                    fileStream.once("close", () => c());
                    fileStream.once("error", (err) => {
                        e(this.wrapError(err, token.isCancelled));
                    });
                    readStream.pipe(fileStream);
                }
            }
            catch (error) {
                e(this.wrapError(error, token.isCancelled));
            }
        });
    }
    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 */);
    }
    async createSymlink(linkContent, des) {
        let linkType = "file";
        if (process.platform === 'win32') {
            if (/\/$/.test(linkContent)) {
                linkType = "dir";
            }
            else {
                let targetPath = linkContent;
                if (!path.isAbsolute(linkContent)) {
                    targetPath = path.join(path.dirname(des), linkContent);
                }
                try {
                    const stat = await util.stat(targetPath);
                    if (stat.isDirectory()) {
                        linkType = "dir";
                    }
                }
                catch (error) {
                    // ignore
                }
            }
        }
        await util.symlink(linkContent, des, linkType);
    }
    isOverwrite() {
        if (this.options &&
            this.options.overwrite) {
            return true;
        }
        return false;
    }
    onEntryCallback(event) {
        if (this.options && this.options.onEntry) {
            this.options.onEntry(event);
        }
    }
    symlinkToFile() {
        let symlinkToFile = false;
        if (process.platform === "win32") {
            if (this.options &&
                this.options.symlinkAsFileOnWindows === false) {
                symlinkToFile = false;
            }
            else {
                symlinkToFile = true;
            }
        }
        return symlinkToFile;
    }
}
exports.Unzip = Unzip;


code:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readlink = exports.symlink = exports.rmdir = exports.access = exports.readdir = exports.chmod = exports.lstat = exports.stat = exports.realpath = exports.mkdir = exports.unlink = void 0;
const fs = require("fs");
const util = require("util");
function unlink(path) {
    return util.promisify(fs.unlink)(path);
}
exports.unlink = unlink;
function mkdir(path, mode) {
    return util.promisify(fs.mkdir)(path, mode);
}
exports.mkdir = mkdir;
function realpath(path) {
    return util.promisify(fs.realpath)(path);
}
exports.realpath = realpath;
function stat(path) {
    return util.promisify(fs.stat)(path);
}
exports.stat = stat;
function lstat(path) {
    return util.promisify(fs.lstat)(path);
}
exports.lstat = lstat;
function chmod(path, mode) {
    return util.promisify(fs.chmod)(path, mode);
}
exports.chmod = chmod;
function readdir(path) {
    return util.promisify(fs.readdir)(path);
}
exports.readdir = readdir;
function access(path, mode) {
    return util.promisify(fs.access)(path, mode);
}
exports.access = access;
function rmdir(path) {
    return util.promisify(fs.rmdir)(path);
}
exports.rmdir = rmdir;
function symlink(target, path, type) {
    return util.promisify(fs.symlink)(target, path, type);
}
exports.symlink = symlink;
function readlink(path) {
    return util.promisify(fs.readlink)(path);
}
exports.readlink = readlink;


code:
import { Cancelable } from "./cancelable";
export interface IZipOptions {
    /**
     * Indicates how to handle when the given path is a symbolic link.
     *
     * `true`: add the target of the symbolic link to the zip.
     *
     * `false`: add symbolic link itself to the zip.
     *
     * The default value is `false`.
     */
    followSymlinks?: boolean;
}
/**
 * Compress files or folders to a zip file.
 */
export declare class Zip extends Cancelable {
    private options?;
    /**
     *
     */
    constructor(options?: IZipOptions | undefined);
    private yazlFile;
    private isPipe;
    private zipStream;
    private zipFiles;
    private zipFolders;
    private token;
    /**
     * Adds a file from the file system at realPath into the zipfile as metadataPath.
     * @param file
     * @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
     * A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
     */
    addFile(file: string, metadataPath?: string): void;
    /**
     * Adds a folder from the file system at realPath into the zipfile as metadataPath.
     * @param folder
     * @param metadataPath Typically metadataPath would be calculated as path.relative(root, realPath).
     * A valid metadataPath must not start with "/" or /[A-Za-z]:\//, and must not contain "..".
     */
    addFolder(folder: string, metadataPath?: string): void;
    /**
     * Generate zip file.
     * @param zipFile the zip file path.
     */
    archive(zipFile: string): Promise<void>;
    /**
     * Cancel compression.
     * If the cancel method is called after the archive is complete, nothing will happen.
     */
    cancel(): void;
    private addEntry;
    private addFileStream;
    private addSymlink;
    private walkDir;
    private stopPipe;
    private followSymlink;
}