node_modules

This commit is contained in:
saeid
2019-07-15 13:07:31 +04:30
parent d3735c6d30
commit ce1a3ebf9c
35713 changed files with 3639219 additions and 1 deletions
+243
View File
@@ -0,0 +1,243 @@
# Change Log
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
<a name="4.6.0"></a>
# [4.6.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.5.4...v4.6.0) (2018-10-31)
### Bug Fixes
* handle undefined and null as stats value ([#302](https://github.com/webpack-contrib/copy-webpack-plugin/issues/302)) ([78c5d12](https://github.com/webpack-contrib/copy-webpack-plugin/commit/78c5d12))
### Features
* add support for target path transform ([#284](https://github.com/webpack-contrib/copy-webpack-plugin/issues/284)) ([7fe0c06](https://github.com/webpack-contrib/copy-webpack-plugin/commit/7fe0c06))
<a name="4.5.4"></a>
## [4.5.4](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.5.3...v4.5.4) (2018-10-18)
### Bug Fixes
* **processPattern:** don't add `'glob'` as directory when it is a file (`contextDependencies`) ([#296](https://github.com/webpack-contrib/copy-webpack-plugin/issues/296)) ([5670926](https://github.com/webpack-contrib/copy-webpack-plugin/commit/5670926))
<a name="4.5.3"></a>
## [4.5.3](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.5.2...v4.5.3) (2018-10-10)
### Bug Fixes
* **processPattern:** add `glob` directory context to `contextDependencies` ([#290](https://github.com/webpack-contrib/copy-webpack-plugin/issues/290)) ([5fa69db](https://github.com/webpack-contrib/copy-webpack-plugin/commit/5fa69db))
<a name="4.5.2"></a>
## [4.5.2](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.5.1...v4.5.2) (2018-06-26)
### Bug Fixes
* allow square brackets in path ([#264](https://github.com/webpack-contrib/copy-webpack-plugin/issues/264)) ([3ef5b6c](https://github.com/webpack-contrib/copy-webpack-plugin/commit/3ef5b6c)), closes [#231](https://github.com/webpack-contrib/copy-webpack-plugin/issues/231)
<a name="4.5.1"></a>
## [4.5.1](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.5.0...v4.5.1) (2018-03-09)
### Bug Fixes
* **package:** update `cacache` v10.0.1...10.0.4 (`dependencies`) ([#238](https://github.com/webpack-contrib/copy-webpack-plugin/issues/238)) ([0b288f9](https://github.com/webpack-contrib/copy-webpack-plugin/commit/0b288f9))
### Performance Improvements
* **index:** switch to `md4` for content hashing ([#239](https://github.com/webpack-contrib/copy-webpack-plugin/issues/239)) ([2be8191](https://github.com/webpack-contrib/copy-webpack-plugin/commit/2be8191))
<a name="4.5.0"></a>
# [4.5.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.4.3...v4.5.0) (2018-03-02)
### Features
* **processPattern:** add support for `{RegExp)` matches (`pattern.test`) ([#235](https://github.com/webpack-contrib/copy-webpack-plugin/issues/235)) ([1861730](https://github.com/webpack-contrib/copy-webpack-plugin/commit/1861730))
<a name="4.4.3"></a>
## [4.4.3](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.4.2...v4.4.3) (2018-03-01)
### Bug Fixes
* **index:** `tapable` deprecation warnings (`webpack >= v4.0.0`) ([#234](https://github.com/webpack-contrib/copy-webpack-plugin/issues/234)) ([445d548](https://github.com/webpack-contrib/copy-webpack-plugin/commit/445d548))
<a name="4.4.2"></a>
## [4.4.2](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.4.1...v4.4.2) (2018-02-23)
### Bug Fixes
* **src/:** don't escape non-glob patterns ([#230](https://github.com/webpack-contrib/copy-webpack-plugin/issues/230)) ([0eb2cd5](https://github.com/webpack-contrib/copy-webpack-plugin/commit/0eb2cd5))
<a name="4.4.1"></a>
## [4.4.1](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.4.0...v4.4.1) (2018-02-08)
### Bug Fixes
* replace `pify` with simpler promise helpers ([#221](https://github.com/webpack-contrib/copy-webpack-plugin/issues/221)) ([dadac24](https://github.com/webpack-contrib/copy-webpack-plugin/commit/dadac24))
<a name="4.4.0"></a>
# [4.4.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.3.1...v4.4.0) (2018-02-08)
### Bug Fixes
* **package:** add `prepare` script ([9bf0d99](https://github.com/webpack-contrib/copy-webpack-plugin/commit/9bf0d99))
* **preProcessPatterns:** support glob context paths with special characters ([#208](https://github.com/webpack-contrib/copy-webpack-plugin/issues/208)) ([ea0c05f](https://github.com/webpack-contrib/copy-webpack-plugin/commit/ea0c05f))
* support `webpack >= v4.0.0` ([6a16b3c](https://github.com/webpack-contrib/copy-webpack-plugin/commit/6a16b3c))
### Features
* use `compiler.inputFileSystem` instead `fs` ([#205](https://github.com/webpack-contrib/copy-webpack-plugin/issues/205)) ([158f821](https://github.com/webpack-contrib/copy-webpack-plugin/commit/158f821))
<a name="4.3.1"></a>
## [4.3.1](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.3.0...v4.3.1) (2017-12-22)
### Bug Fixes
* `cache` behaviour ([#196](https://github.com/webpack-contrib/copy-webpack-plugin/issues/196)) ([6beb89e](https://github.com/webpack-contrib/copy-webpack-plugin/commit/6beb89e))
* `cache` option behaviour ([3b088d0](https://github.com/webpack-contrib/copy-webpack-plugin/commit/3b088d0))
<a name="4.3.0"></a>
# [4.3.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.2.4...v4.3.0) (2017-12-14)
### Features
* add option to cache `pattern.transform` (`pattern.cache`) ([#176](https://github.com/webpack-contrib/copy-webpack-plugin/issues/176)) ([20c143b](https://github.com/webpack-contrib/copy-webpack-plugin/commit/20c143b))
* option for caching `transform` function ([48c19ff](https://github.com/webpack-contrib/copy-webpack-plugin/commit/48c19ff))
<a name="4.2.4"></a>
## [4.2.4](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.2.3...v4.2.4) (2017-12-14)
### Refactoring
* refactor: use native `{Promise}` instead of `bluebird` ([#178](https://github.com/webpack-contrib/copy-webpack-plugin/issues/178)) ([a508f14](https://github.com/webpack-contrib/copy-webpack-plugin/commit/a508f14))
<a name="4.2.3"></a>
## [4.2.3](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.2.2...v4.2.3) (2017-11-23)
<a name="4.2.2"></a>
## [4.2.2](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.2.0...v4.2.2) (2017-11-23)
### Bug Fixes
* copying same file to multiple targets ([#165](https://github.com/webpack-contrib/copy-webpack-plugin/issues/165)) ([43a9870](https://github.com/webpack-contrib/copy-webpack-plugin/commit/43a9870))
<a name="4.2.0"></a>
# [4.2.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.1.1...v4.2.0) (2017-10-19)
### Features
* add `context` option (`options.context`) ([#149](https://github.com/webpack-contrib/copy-webpack-plugin/issues/149)) ([10cd1a2](https://github.com/webpack-contrib/copy-webpack-plugin/commit/10cd1a2))
* allow async transforms ([#111](https://github.com/webpack-contrib/copy-webpack-plugin/issues/111)) ([8794e5f](https://github.com/webpack-contrib/copy-webpack-plugin/commit/8794e5f))
* Plugin context option ([5c54e92](https://github.com/webpack-contrib/copy-webpack-plugin/commit/5c54e92)), closes [#148](https://github.com/webpack-contrib/copy-webpack-plugin/issues/148)
* support `{String}` patterns ([#155](https://github.com/webpack-contrib/copy-webpack-plugin/issues/155)) ([b6c2e66](https://github.com/webpack-contrib/copy-webpack-plugin/commit/b6c2e66))
* Support simple string patterns ([056a60b](https://github.com/webpack-contrib/copy-webpack-plugin/commit/056a60b)), closes [#150](https://github.com/webpack-contrib/copy-webpack-plugin/issues/150)
<a name="4.1.1"></a>
## [4.1.1](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.1.0...v4.1.1) (2017-10-05)
### Chore
* Update dependencies for NSP security advisory ([#151](https://github.com/webpack-contrib/copy-webpack-plugin/issues/151)) ([6d4346e](https://github.com/webpack-contrib/copy-webpack-plugin/commit/6d4346e))
- Reference issue: https://nodesecurity.io/advisories/minimatch_regular-expression-denial-of-service
<a name="4.1.0"></a>
# [4.1.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v2.1.3...v4.1.0) (2017-09-29)
### Bug Fixes
* Changed default ignore glob to ignore dot files ([#80](https://github.com/webpack-contrib/copy-webpack-plugin/issues/80)) ([08b69a4](https://github.com/webpack-contrib/copy-webpack-plugin/commit/08b69a4))
* Fixed glob as object ([1b2c21a](https://github.com/webpack-contrib/copy-webpack-plugin/commit/1b2c21a))
* Improved Windows compatibility ([#85](https://github.com/webpack-contrib/copy-webpack-plugin/issues/85)) ([ad62899](https://github.com/webpack-contrib/copy-webpack-plugin/commit/ad62899))
* Memory leak in watch mode and use Set for performance ([#130](https://github.com/webpack-contrib/copy-webpack-plugin/issues/130)) ([de46fde](https://github.com/webpack-contrib/copy-webpack-plugin/commit/de46fde))
* subdirectory errors in blob patterns ([c2720d0](https://github.com/webpack-contrib/copy-webpack-plugin/commit/c2720d0))
### Features
* Added non-wildcard glob support ([405d1ec](https://github.com/webpack-contrib/copy-webpack-plugin/commit/405d1ec))
* Added transform method to patterns ([#77](https://github.com/webpack-contrib/copy-webpack-plugin/issues/77)) ([6371eb1](https://github.com/webpack-contrib/copy-webpack-plugin/commit/6371eb1))
<a name="4.0.1"></a>
## [4.0.1](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v2.1.3...v4.0.1) (2017-09-29)
### Bug Fixes
* Fixed glob as object ([1b2c21a](https://github.com/webpack-contrib/copy-webpack-plugin/commit/1b2c21a))
* Improved Windows compatibility ([#85](https://github.com/webpack-contrib/copy-webpack-plugin/issues/85)) ([ad62899](https://github.com/webpack-contrib/copy-webpack-plugin/commit/ad62899))
* subdirectory errors in blob patterns ([c2720d0](https://github.com/webpack-contrib/copy-webpack-plugin/commit/c2720d0))
### Features
* Added non-wildcard glob support ([405d1ec](https://github.com/webpack-contrib/copy-webpack-plugin/commit/405d1ec))
* Added transform method to patterns ([#77](https://github.com/webpack-contrib/copy-webpack-plugin/issues/77)) ([6371eb1](https://github.com/webpack-contrib/copy-webpack-plugin/commit/6371eb1))
<a name="4.0.0"></a>
## [4.0.0](https://github.com/webpack-contrib/copy-webpack-plugin/compare/v4.0.0...v3.0.1) (2016-10-23)
### Bug Fixes
* Changed default ignore glob to ignore dot files ([#80](https://github.com/webpack-contrib/copy-webpack-plugin/issues/80)) ([08b69a4](https://github.com/webpack-contrib/copy-webpack-plugin/commit/08b69a4))
### Features
* Added transform method to patterns ([6371eb1](https://github.com/webpack-contrib/copy-webpack-plugin/commit/6371eb1))
+20
View File
@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+449
View File
@@ -0,0 +1,449 @@
[![npm][npm]][npm-url]
[![node][node]][node-url]
[![deps][deps]][deps-url]
[![test][test]][test-url]
[![coverage][cover]][cover-url]
[![chat][chat]][chat-url]
<div align="center">
<a href="https://github.com/webpack/webpack">
<img width="200" height="200"
src="https://webpack.js.org/assets/icon-square-big.svg">
</a>
<h1>Copy Webpack Plugin</h1>
<p>Copies individual files or entire directories to the build directory</p>
</div>
<h2 align="center">Install</h2>
```bash
npm i -D copy-webpack-plugin
```
<h2 align="center">Usage</h2>
**webpack.config.js**
```js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const config = {
plugins: [
new CopyWebpackPlugin([ ...patterns ], options)
]
}
```
> ℹ️ If you want `webpack-dev-server` to write files to the output directory during development, you can force it with the [`write-file-webpack-plugin`](https://github.com/gajus/write-file-webpack-plugin).
### `Patterns`
A simple pattern looks like this
```js
{ from: 'source', to: 'dest' }
```
Or, in case of just a `from` with the default destination, you can also use a `{String}` as shorthand instead of an `{Object}`
```js
'source'
```
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|[`from`](#from)|`{String\|Object}`|`undefined`|Globs accept [minimatch options](https://github.com/isaacs/minimatch)|
|[`fromArgs`](#fromArgs)|`{Object}`|`{ cwd: context }`|See the [`node-glob` options](https://github.com/isaacs/node-glob#options) in addition to the ones below|
|[`to`](#to)|`{String\|Object}`|`undefined`|Output root if `from` is file or dir, resolved glob path if `from` is glob|
|[`toType`](#toType)|`{String}`|``|[toType Options](#totype)|
|[`test`](#test)|`{RegExp}`|``|Pattern for extracting elements to be used in `to` templates|
|[`force`](#force)|`{Boolean}`|`false`|Overwrites files already in `compilation.assets` (usually added by other plugins/loaders)|
|[`ignore`](#ignore)|`{Array}`|`[]`|Globs to ignore for this pattern|
|`flatten`|`{Boolean}`|`false`|Removes all directory references and only copies file names.⚠️ If files have the same name, the result is non-deterministic|
|[`transform`](#transform)|`{Function\|Promise}`|`(content, path) => content`|Function or Promise that modifies file contents before copying|
|[`transformPath`](#transformPath)|`{Function\|Promise}`|`(targetPath, sourcePath) => path`|Function or Promise that modifies file writing path|
|[`cache`](#cache)|`{Boolean\|Object}`|`false`|Enable `transform` caching. You can use `{ cache: { key: 'my-cache-key' } }` to invalidate the cache|
|[`context`](#context)|`{String}`|`options.context \|\| compiler.options.context`|A path that determines how to interpret the `from` path|
### `from`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
'relative/path/to/file.ext',
'/absolute/path/to/file.ext',
'relative/path/to/dir',
'/absolute/path/to/dir',
'**/*',
{ glob: '\*\*/\*', dot: true }
], options)
]
```
### `to`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{ from: '**/*', to: 'relative/path/to/dest/' },
{ from: '**/*', to: '/absolute/path/to/dest/' }
], options)
]
```
### `toType`
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|**`'dir'`**|`{String}`|`undefined`|If `from` is directory, `to` has no extension or ends in `'/'`|
|**`'file'`**|`{String}`|`undefined`|If `to` has extension or `from` is file|
|**`'template'`**|`{String}`|`undefined`|If `to` contains [a template pattern](https://github.com/webpack-contrib/file-loader#placeholders)|
#### `'dir'`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'path/to/file.txt',
to: 'directory/with/extension.ext',
toType: 'dir'
}
], options)
]
```
#### `'file'`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'path/to/file.txt',
to: 'file/without/extension',
toType: 'file'
},
], options)
]
```
#### `'template'`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'src/',
to: 'dest/[name].[hash].[ext]',
toType: 'template'
}
], options)
]
```
### `test`
Defines a `{RegExp}` to match some parts of the file path.
These capture groups can be reused in the name property using `[N]` placeholder.
Note that `[0]` will be replaced by the entire path of the file,
whereas `[1]` will contain the first capturing parenthesis of your `{RegExp}`
and so on...
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: '*/*',
to: '[1]-[2].[hash].[ext]',
test: /([^/]+)\/(.+)\.png$/
}
], options)
]
```
### `force`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{ from: 'src/**/*', to: 'dest/', force: true }
], options)
]
```
### `ignore`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{ from: 'src/**/*', to: 'dest/', ignore: [ '*.js' ] }
], options)
]
```
### `flatten`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{ from: 'src/**/*', to: 'dest/', flatten: true }
], options)
]
```
### `transform`
#### `{Function}`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'src/*.png',
to: 'dest/',
transform (content, path) {
return optimize(content)
}
}
], options)
]
```
#### `{Promise}`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'src/*.png',
to: 'dest/',
transform (content, path) {
return Promise.resolve(optimize(content))
}
}
], options)
]
```
### `transformPath`
#### `{Function}`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'src/*.png',
to: 'dest/',
transformPath (targetPath, absolutePath) {
return 'newPath';
}
}
], options)
]
```
#### `{Promise}`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'src/*.png',
to: 'dest/',
transform (targePath, absolutePath) {
return Promise.resolve('newPath')
}
}
], options)
]
```
### `cache`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{
from: 'src/*.png',
to: 'dest/',
transform (content, path) {
return optimize(content)
},
cache: true
}
], options)
]
```
### `context`
**webpack.config.js**
```js
[
new CopyWebpackPlugin([
{ from: 'src/*.txt', to: 'dest/', context: 'app/' }
], options)
]
```
<h2 align="center">Options</h2>
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|[`debug`](#debug)|`{String}`|**`'warning'`**|[Debug Options](#debug)|
|[`ignore`](#ignore)|`{Array}`|`[]`|Array of globs to ignore (applied to `from`)|
|[`context`](#context)|`{String}`|`compiler.options.context`|A path that determines how to interpret the `from` path, shared for all patterns|
|[`copyUnmodified`](#copyUnmodified)|`{Boolean}`|`false`|Copies files, regardless of modification when using watch or `webpack-dev-server`. All files are copied on first build, regardless of this option|
### `debug`
|Name|Type|Default|Description|
|:--:|:--:|:-----:|:----------|
|**`'info'`**|`{String\|Boolean}`|`false`|File location and read info|
|**`'debug'`**|`{String}`|`false`|Very detailed debugging info|
|**`'warning'`**|`{String}`|`true`|Only warnings|
#### `'info'`
**webpack.config.js**
```js
[
new CopyWebpackPlugin(
[ ...patterns ],
{ debug: 'info' }
)
]
```
#### `'debug'`
**webpack.config.js**
```js
[
new CopyWebpackPlugin(
[ ...patterns ],
{ debug: 'debug' }
)
]
```
#### `'warning' (default)`
**webpack.config.js**
```js
[
new CopyWebpackPlugin(
[ ...patterns ],
{ debug: true }
)
]
```
### `ignore`
**webpack.config.js**
```js
[
new CopyWebpackPlugin(
[ ...patterns ],
{ ignore: [ '*.js', '*.css' ] }
)
]
```
### `context`
**webpack.config.js**
```js
[
new CopyWebpackPlugin(
[ ...patterns ],
{ context: '/app' }
)
]
```
### `copyUnmodified`
> ℹ️ By default, we only copy **modified** files during a `webpack --watch` or `webpack-dev-server` build. Setting this option to `true` will copy all files.
**webpack.config.js**
```js
[
new CopyWebpackPlugin(
[ ...patterns ],
{ copyUnmodified: true }
)
]
```
<h2 align="center">Maintainers</h2>
<table>
<tbody>
<tr>
<td align="center">
<a href="https://github.com/bebraw">
<img width="150" height="150" src="https://github.com/bebraw.png?v=3&s=150">
</br>
Juho Vepsäläinen
</a>
</td>
<td align="center">
<a href="https://github.com/d3viant0ne">
<img width="150" height="150" src="https://github.com/d3viant0ne.png?v=3&s=150">
</br>
Joshua Wiens
</a>
</td>
<td align="center">
<a href="https://github.com/michael-ciniawsky">
<img width="150" height="150" src="https://github.com/michael-ciniawsky.png?v=3&s=150">
</br>
Michael Ciniawsky
</a>
</td>
<td align="center">
<a href="https://github.com/evilebottnawi">
<img width="150" height="150" src="https://github.com/evilebottnawi.png?v=3&s=150">
</br>
Alexander Krasnoyarov
</a>
</td>
</tr>
<tbody>
</table>
[npm]: https://img.shields.io/npm/v/copy-webpack-plugin.svg
[npm-url]: https://npmjs.com/package/copy-webpack-plugin
[node]: https://img.shields.io/node/v/copy-webpack-plugin.svg
[node-url]: https://nodejs.org
[deps]: https://david-dm.org/webpack-contrib/copy-webpack-plugin.svg
[deps-url]: https://david-dm.org/webpack-contrib/copy-webpack-plugin
[test]: https://secure.travis-ci.org/webpack-contrib/copy-webpack-plugin.svg
[test-url]: http://travis-ci.org/webpack-contrib/copy-webpack-plugin
[cover]: https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/branch/master/graph/badge.svg
[cover-url]: https://codecov.io/gh/webpack-contrib/copy-webpack-plugin
[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg
[chat-url]: https://gitter.im/webpack/webpack
+240
View File
@@ -0,0 +1,240 @@
'use strict';
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _preProcessPattern = require('./preProcessPattern');
var _preProcessPattern2 = _interopRequireDefault(_preProcessPattern);
var _processPattern = require('./processPattern');
var _processPattern2 = _interopRequireDefault(_processPattern);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function CopyWebpackPlugin() {
var patterns = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (!Array.isArray(patterns)) {
throw new Error('[copy-webpack-plugin] patterns must be an array');
}
// Defaults debug level to 'warning'
options.debug = options.debug || 'warning';
// Defaults debugging to info if only true is specified
if (options.debug === true) {
options.debug = 'info';
}
var debugLevels = ['warning', 'info', 'debug'];
var debugLevelIndex = debugLevels.indexOf(options.debug);
function log(msg, level) {
if (level === 0) {
msg = 'WARNING - ' + msg;
} else {
level = level || 1;
}
if (level <= debugLevelIndex) {
console.log('[copy-webpack-plugin] ' + msg); // eslint-disable-line no-console
}
}
function warning(msg) {
log(msg, 0);
}
function info(msg) {
log(msg, 1);
}
function debug(msg) {
log(msg, 2);
}
var apply = function apply(compiler) {
var fileDependencies = void 0;
var contextDependencies = void 0;
var written = {};
var context = void 0;
if (!options.context) {
context = compiler.options.context;
} else if (!_path2.default.isAbsolute(options.context)) {
context = _path2.default.join(compiler.options.context, options.context);
} else {
context = options.context;
}
var emit = function emit(compilation, cb) {
debug('starting emit');
var callback = function callback() {
debug('finishing emit');
cb();
};
fileDependencies = [];
contextDependencies = [];
var globalRef = {
info: info,
debug: debug,
warning: warning,
compilation: compilation,
written: written,
fileDependencies: fileDependencies,
contextDependencies: contextDependencies,
context: context,
inputFileSystem: compiler.inputFileSystem,
output: compiler.options.output.path,
ignore: options.ignore || [],
copyUnmodified: options.copyUnmodified,
concurrency: options.concurrency
};
if (globalRef.output === '/' && compiler.options.devServer && compiler.options.devServer.outputPath) {
globalRef.output = compiler.options.devServer.outputPath;
}
var tasks = [];
patterns.forEach(function (pattern) {
tasks.push(Promise.resolve().then(function () {
return (0, _preProcessPattern2.default)(globalRef, pattern);
})
// Every source (from) is assumed to exist here
.then(function (pattern) {
return (0, _processPattern2.default)(globalRef, pattern);
}));
});
Promise.all(tasks).catch(function (err) {
compilation.errors.push(err);
}).then(function () {
return callback();
});
};
var afterEmit = function afterEmit(compilation, cb) {
debug('starting after-emit');
var callback = function callback() {
debug('finishing after-emit');
cb();
};
var compilationFileDependencies = void 0;
var addFileDependency = void 0;
if (Array.isArray(compilation.fileDependencies)) {
compilationFileDependencies = new Set(compilation.fileDependencies);
addFileDependency = function addFileDependency(file) {
return compilation.fileDependencies.push(file);
};
} else {
compilationFileDependencies = compilation.fileDependencies;
addFileDependency = function addFileDependency(file) {
return compilation.fileDependencies.add(file);
};
}
var compilationContextDependencies = void 0;
var addContextDependency = void 0;
if (Array.isArray(compilation.contextDependencies)) {
compilationContextDependencies = new Set(compilation.contextDependencies);
addContextDependency = function addContextDependency(file) {
return compilation.contextDependencies.push(file);
};
} else {
compilationContextDependencies = compilation.contextDependencies;
addContextDependency = function addContextDependency(file) {
return compilation.contextDependencies.add(file);
};
}
// Add file dependencies if they're not already tracked
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = fileDependencies[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var file = _step.value;
if (compilationFileDependencies.has(file)) {
debug('not adding ' + file + ' to change tracking, because it\'s already tracked');
} else {
debug('adding ' + file + ' to change tracking');
addFileDependency(file);
}
}
// Add context dependencies if they're not already tracked
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = contextDependencies[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _context = _step2.value;
if (compilationContextDependencies.has(_context)) {
debug('not adding ' + _context + ' to change tracking, because it\'s already tracked');
} else {
debug('adding ' + _context + ' to change tracking');
addContextDependency(_context);
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
callback();
};
if (compiler.hooks) {
var plugin = { name: 'CopyPlugin' };
compiler.hooks.emit.tapAsync(plugin, emit);
compiler.hooks.afterEmit.tapAsync(plugin, afterEmit);
} else {
compiler.plugin('emit', emit);
compiler.plugin('after-emit', afterEmit);
}
};
return {
apply: apply
};
}
CopyWebpackPlugin['default'] = CopyWebpackPlugin;
module.exports = CopyWebpackPlugin;
+139
View File
@@ -0,0 +1,139 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = preProcessPattern;
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _isGlob = require('is-glob');
var _isGlob2 = _interopRequireDefault(_isGlob);
var _escape = require('./utils/escape');
var _escape2 = _interopRequireDefault(_escape);
var _isObject = require('./utils/isObject');
var _isObject2 = _interopRequireDefault(_isObject);
var _promisify = require('./utils/promisify');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// https://www.debuggex.com/r/VH2yS2mvJOitiyr3
var isTemplateLike = /(\[ext\])|(\[name\])|(\[path\])|(\[folder\])|(\[emoji(:\d+)?\])|(\[(\w+:)?hash(:\w+)?(:\d+)?\])|(\[\d+\])/;
function preProcessPattern(globalRef, pattern) {
var info = globalRef.info,
debug = globalRef.debug,
warning = globalRef.warning,
context = globalRef.context,
inputFileSystem = globalRef.inputFileSystem,
fileDependencies = globalRef.fileDependencies,
contextDependencies = globalRef.contextDependencies,
compilation = globalRef.compilation;
pattern = typeof pattern === 'string' ? {
from: pattern
} : Object.assign({}, pattern);
pattern.to = pattern.to || '';
pattern.context = pattern.context || context;
if (!_path2.default.isAbsolute(pattern.context)) {
pattern.context = _path2.default.join(context, pattern.context);
}
pattern.ignore = globalRef.ignore.concat(pattern.ignore || []);
info('processing from: \'' + pattern.from + '\' to: \'' + pattern.to + '\'');
switch (true) {
case !!pattern.toType:
// if toType already exists
break;
case isTemplateLike.test(pattern.to):
pattern.toType = 'template';
break;
case _path2.default.extname(pattern.to) === '' || pattern.to.slice(-1) === '/':
pattern.toType = 'dir';
break;
default:
pattern.toType = 'file';
}
debug('determined \'' + pattern.to + '\' is a \'' + pattern.toType + '\'');
// If we know it's a glob, then bail early
if ((0, _isObject2.default)(pattern.from) && pattern.from.glob) {
pattern.fromType = 'glob';
var fromArgs = Object.assign({}, pattern.from);
delete fromArgs.glob;
pattern.fromArgs = fromArgs;
pattern.glob = (0, _escape2.default)(pattern.context, pattern.from.glob);
pattern.absoluteFrom = _path2.default.resolve(pattern.context, pattern.from.glob);
return Promise.resolve(pattern);
}
if (_path2.default.isAbsolute(pattern.from)) {
pattern.absoluteFrom = pattern.from;
} else {
pattern.absoluteFrom = _path2.default.resolve(pattern.context, pattern.from);
}
debug('determined \'' + pattern.from + '\' to be read from \'' + pattern.absoluteFrom + '\'');
var noStatsHandler = function noStatsHandler() {
// If from doesn't appear to be a glob, then log a warning
if ((0, _isGlob2.default)(pattern.from) || pattern.from.indexOf('*') !== -1) {
pattern.fromType = 'glob';
pattern.glob = (0, _escape2.default)(pattern.context, pattern.from);
} else {
var msg = 'unable to locate \'' + pattern.from + '\' at \'' + pattern.absoluteFrom + '\'';
var warningMsg = '[copy-webpack-plugin] ' + msg;
// only display the same message once
if (compilation.errors.indexOf(warningMsg) === -1) {
warning(msg);
compilation.errors.push(warningMsg);
}
pattern.fromType = 'nonexistent';
}
};
return (0, _promisify.stat)(inputFileSystem, pattern.absoluteFrom).catch(function () {
return noStatsHandler();
}).then(function (stat) {
if (!stat) {
noStatsHandler();
return pattern;
}
if (stat.isDirectory()) {
pattern.fromType = 'dir';
pattern.context = pattern.absoluteFrom;
contextDependencies.push(pattern.absoluteFrom);
pattern.glob = (0, _escape2.default)(pattern.absoluteFrom, '**/*');
pattern.absoluteFrom = _path2.default.join(pattern.absoluteFrom, '**/*');
pattern.fromArgs = {
dot: true
};
} else if (stat.isFile()) {
pattern.fromType = 'file';
pattern.context = _path2.default.dirname(pattern.absoluteFrom);
pattern.glob = (0, _escape2.default)(pattern.absoluteFrom);
pattern.fromArgs = {
dot: true
};
fileDependencies.push(pattern.absoluteFrom);
} else if (!pattern.fromType) {
info('Unrecognized file type for ' + pattern.from);
}
return pattern;
});
}
+138
View File
@@ -0,0 +1,138 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = processPattern;
var _globby = require('globby');
var _globby2 = _interopRequireDefault(_globby);
var _pLimit = require('p-limit');
var _pLimit2 = _interopRequireDefault(_pLimit);
var _isGlob = require('is-glob');
var _isGlob2 = _interopRequireDefault(_isGlob);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _minimatch = require('minimatch');
var _minimatch2 = _interopRequireDefault(_minimatch);
var _writeFile = require('./writeFile');
var _writeFile2 = _interopRequireDefault(_writeFile);
var _isObject = require('./utils/isObject');
var _isObject2 = _interopRequireDefault(_isObject);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function processPattern(globalRef, pattern) {
var info = globalRef.info,
debug = globalRef.debug,
output = globalRef.output,
concurrency = globalRef.concurrency,
contextDependencies = globalRef.contextDependencies;
var globArgs = Object.assign({
cwd: pattern.context
}, pattern.fromArgs || {});
if (pattern.fromType === 'nonexistent') {
return Promise.resolve();
}
var limit = (0, _pLimit2.default)(concurrency || 100);
info('begin globbing \'' + pattern.glob + '\' with a context of \'' + pattern.context + '\'');
return (0, _globby2.default)(pattern.glob, globArgs).then(function (paths) {
return Promise.all(paths.map(function (from) {
return limit(function () {
var file = {
force: pattern.force,
absoluteFrom: _path2.default.resolve(pattern.context, from)
};
file.relativeFrom = _path2.default.relative(pattern.context, file.absoluteFrom);
if (pattern.flatten) {
file.relativeFrom = _path2.default.basename(file.relativeFrom);
}
// This is so webpack is able to watch the directory and when
// a new file is added it triggeres a rebuild
var contextPath = _path2.default.dirname(_path2.default.resolve(from));
if (contextDependencies.indexOf(contextPath) === -1 && (0, _isGlob2.default)(pattern.glob)) {
contextDependencies.push(contextPath);
}
debug('found ' + from);
// Check the ignore list
var il = pattern.ignore.length;
while (il--) {
var ignoreGlob = pattern.ignore[il];
var globParams = {
dot: true,
matchBase: true
};
var glob = void 0;
if (typeof ignoreGlob === 'string') {
glob = ignoreGlob;
} else if ((0, _isObject2.default)(ignoreGlob)) {
glob = ignoreGlob.glob || '';
var ignoreGlobParams = Object.assign({}, ignoreGlob);
delete ignoreGlobParams.glob;
// Overwrite minimatch defaults
globParams = Object.assign(globParams, ignoreGlobParams);
} else {
glob = '';
}
debug('testing ' + glob + ' against ' + file.relativeFrom);
if ((0, _minimatch2.default)(file.relativeFrom, glob, globParams)) {
info('ignoring \'' + file.relativeFrom + '\', because it matches the ignore glob \'' + glob + '\'');
return Promise.resolve();
} else {
debug(glob + ' doesn\'t match ' + file.relativeFrom);
}
}
// Change the to path to be relative for webpack
if (pattern.toType === 'dir') {
file.webpackTo = _path2.default.join(pattern.to, file.relativeFrom);
} else if (pattern.toType === 'file') {
file.webpackTo = pattern.to || file.relativeFrom;
} else if (pattern.toType === 'template') {
file.webpackTo = pattern.to;
file.webpackToRegExp = pattern.test;
}
if (_path2.default.isAbsolute(file.webpackTo)) {
if (output === '/') {
throw '[copy-webpack-plugin] Using older versions of webpack-dev-server, devServer.outputPath must be defined to write to absolute paths';
}
file.webpackTo = _path2.default.relative(output, file.webpackTo);
}
// ensure forward slashes
file.webpackTo = file.webpackTo.replace(/\\/g, '/');
info('determined that \'' + from + '\' should write to \'' + file.webpackTo + '\'');
return (0, _writeFile2.default)(globalRef, pattern, file);
});
}));
});
}
+35
View File
@@ -0,0 +1,35 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = escape;
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function escape(context, from) {
if (from && _path2.default.isAbsolute(from)) {
return from;
} else {
// Ensure context is escaped before globbing
// Handles special characters in paths
var absoluteContext = _path2.default.resolve(context).replace(/[\*|\?|\!|\(|\)|\[|\]|\{|\}]/g, function (substring) {
return '[' + substring + ']';
});
if (!from) {
return absoluteContext;
}
// Cannot use path.join/resolve as it "fixes" the path separators
if (absoluteContext.endsWith('/')) {
return '' + absoluteContext + from;
} else {
return absoluteContext + '/' + from;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (val) {
return Object.prototype.toString.call(val) === '[object Object]' ? true : false;
};
+26
View File
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var stat = exports.stat = function stat(inputFileSystem, path) {
return new Promise(function (resolve, reject) {
inputFileSystem.stat(path, function (err, stats) {
if (err) {
reject(err);
}
resolve(stats);
});
});
};
var readFile = exports.readFile = function readFile(inputFileSystem, path) {
return new Promise(function (resolve, reject) {
inputFileSystem.readFile(path, function (err, stats) {
if (err) {
reject(err);
}
resolve(stats);
});
});
};
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (inputFileSystem, path) {
return new Promise(function (resolve, reject) {
inputFileSystem.readFile(path, function (err, stats) {
if (err) {
return reject(err);
}
return resolve(stats);
});
});
};
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (inputFileSystem, path) {
return new Promise(function (resolve, reject) {
inputFileSystem.readFile(path, function (err, stats) {
if (err) {
return reject(err);
}
return resolve(stats);
});
});
};
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (inputFileSystem, path) {
return new Promise(function (resolve, reject) {
inputFileSystem.stat(path, function (err, stats) {
if (err) {
return reject(err);
}
return resolve(stats);
});
});
};
+153
View File
@@ -0,0 +1,153 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = writeFile;
var _loaderUtils = require('loader-utils');
var _loaderUtils2 = _interopRequireDefault(_loaderUtils);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _cacache = require('cacache');
var _cacache2 = _interopRequireDefault(_cacache);
var _serializeJavascript = require('serialize-javascript');
var _serializeJavascript2 = _interopRequireDefault(_serializeJavascript);
var _package = require('../package.json');
var _findCacheDir = require('find-cache-dir');
var _findCacheDir2 = _interopRequireDefault(_findCacheDir);
var _promisify = require('./utils/promisify');
var _crypto = require('crypto');
var _crypto2 = _interopRequireDefault(_crypto);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function writeFile(globalRef, pattern, file) {
var info = globalRef.info,
debug = globalRef.debug,
compilation = globalRef.compilation,
fileDependencies = globalRef.fileDependencies,
written = globalRef.written,
inputFileSystem = globalRef.inputFileSystem,
copyUnmodified = globalRef.copyUnmodified;
return (0, _promisify.stat)(inputFileSystem, file.absoluteFrom).then(function (stat) {
// We don't write empty directories
if (stat.isDirectory()) {
return;
}
// If this came from a glob, add it to the file watchlist
if (pattern.fromType === 'glob') {
fileDependencies.push(file.absoluteFrom);
}
info('reading ' + file.absoluteFrom + ' to write to assets');
return (0, _promisify.readFile)(inputFileSystem, file.absoluteFrom).then(function (content) {
if (pattern.transform) {
var transform = function transform(content, absoluteFrom) {
return pattern.transform(content, absoluteFrom);
};
if (pattern.cache) {
if (!globalRef.cacheDir) {
globalRef.cacheDir = (0, _findCacheDir2.default)({ name: 'copy-webpack-plugin' });
}
var cacheKey = pattern.cache.key ? pattern.cache.key : (0, _serializeJavascript2.default)({
name: _package.name,
version: _package.version,
pattern: pattern,
hash: _crypto2.default.createHash('md4').update(content).digest('hex')
});
return _cacache2.default.get(globalRef.cacheDir, cacheKey).then(function (result) {
return result.data;
}, function () {
return Promise.resolve().then(function () {
return transform(content, file.absoluteFrom);
}).then(function (content) {
return _cacache2.default.put(globalRef.cacheDir, cacheKey, content).then(function () {
return content;
});
});
});
}
content = transform(content, file.absoluteFrom);
}
return content;
}).then(function (content) {
if (pattern.toType === 'template') {
info('interpolating template \'' + file.webpackTo + '\' for \'' + file.relativeFrom + '\'');
// If it doesn't have an extension, remove it from the pattern
// ie. [name].[ext] or [name][ext] both become [name]
if (!_path2.default.extname(file.relativeFrom)) {
file.webpackTo = file.webpackTo.replace(/\.?\[ext\]/g, '');
}
file.webpackTo = _loaderUtils2.default.interpolateName({ resourcePath: file.absoluteFrom }, file.webpackTo, {
content: content,
regExp: file.webpackToRegExp,
context: pattern.context
});
}
return content;
}).then(function (content) {
if (pattern.transformPath) {
return Promise.resolve(pattern.transformPath(file.webpackTo, file.absoluteFrom)).then(function (newPath) {
file.webpackTo = newPath;
}).then(function () {
return content;
});
}
return content;
}).then(function (content) {
var hash = _loaderUtils2.default.getHashDigest(content);
if (!copyUnmodified && written[file.absoluteFrom] && written[file.absoluteFrom]['hash'] === hash && written[file.absoluteFrom]['webpackTo'] === file.webpackTo) {
info('skipping \'' + file.webpackTo + '\', because it hasn\'t changed');
return;
} else {
debug('added ' + hash + ' to written tracking for \'' + file.absoluteFrom + '\'');
written[file.absoluteFrom] = {
hash: hash,
webpackTo: file.webpackTo
};
}
if (compilation.assets[file.webpackTo] && !file.force) {
info('skipping \'' + file.webpackTo + '\', because it already exists');
return;
}
info('writing \'' + file.webpackTo + '\' to compilation assets from \'' + file.absoluteFrom + '\'');
compilation.assets[file.webpackTo] = {
size: function size() {
return stat.size;
},
source: function source() {
return content;
}
};
});
});
}
+478
View File
@@ -0,0 +1,478 @@
# Change Log
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
<a name="10.0.4"></a>
## [10.0.4](https://github.com/zkat/cacache/compare/v10.0.3...v10.0.4) (2018-02-16)
<a name="10.0.3"></a>
## [10.0.3](https://github.com/zkat/cacache/compare/v10.0.2...v10.0.3) (2018-02-16)
### Bug Fixes
* **content:** rethrow aggregate errors as ENOENT ([fa918f5](https://github.com/zkat/cacache/commit/fa918f5))
<a name="10.0.2"></a>
## [10.0.2](https://github.com/zkat/cacache/compare/v10.0.1...v10.0.2) (2018-01-07)
### Bug Fixes
* **ls:** deleted entries could cause a premature stream EOF ([347dc36](https://github.com/zkat/cacache/commit/347dc36))
<a name="10.0.1"></a>
## [10.0.1](https://github.com/zkat/cacache/compare/v10.0.0...v10.0.1) (2017-11-15)
### Bug Fixes
* **move-file:** actually use the fallback to `move-concurrently` (#110) ([073fbe1](https://github.com/zkat/cacache/commit/073fbe1))
<a name="10.0.0"></a>
# [10.0.0](https://github.com/zkat/cacache/compare/v9.3.0...v10.0.0) (2017-10-23)
### Features
* **license:** relicense to ISC (#111) ([fdbb4e5](https://github.com/zkat/cacache/commit/fdbb4e5))
### Performance Improvements
* more copyFile benchmarks ([63787bb](https://github.com/zkat/cacache/commit/63787bb))
### BREAKING CHANGES
* **license:** the license has been changed from CC0-1.0 to ISC.
<a name="9.3.0"></a>
# [9.3.0](https://github.com/zkat/cacache/compare/v9.2.9...v9.3.0) (2017-10-07)
### Features
* **copy:** added cacache.get.copy api for fast copies (#107) ([067b5f6](https://github.com/zkat/cacache/commit/067b5f6))
<a name="9.2.9"></a>
## [9.2.9](https://github.com/zkat/cacache/compare/v9.2.8...v9.2.9) (2017-06-17)
<a name="9.2.8"></a>
## [9.2.8](https://github.com/zkat/cacache/compare/v9.2.7...v9.2.8) (2017-06-05)
### Bug Fixes
* **ssri:** bump ssri for bugfix ([c3232ea](https://github.com/zkat/cacache/commit/c3232ea))
<a name="9.2.7"></a>
## [9.2.7](https://github.com/zkat/cacache/compare/v9.2.6...v9.2.7) (2017-06-05)
### Bug Fixes
* **content:** make verified content completely read-only (#96) ([4131196](https://github.com/zkat/cacache/commit/4131196))
<a name="9.2.6"></a>
## [9.2.6](https://github.com/zkat/cacache/compare/v9.2.5...v9.2.6) (2017-05-31)
### Bug Fixes
* **node:** update ssri to prevent old node 4 crash ([5209ffe](https://github.com/zkat/cacache/commit/5209ffe))
<a name="9.2.5"></a>
## [9.2.5](https://github.com/zkat/cacache/compare/v9.2.4...v9.2.5) (2017-05-25)
### Bug Fixes
* **deps:** fix lockfile issues and bump ssri ([84e1d7e](https://github.com/zkat/cacache/commit/84e1d7e))
<a name="9.2.4"></a>
## [9.2.4](https://github.com/zkat/cacache/compare/v9.2.3...v9.2.4) (2017-05-24)
### Bug Fixes
* **deps:** bumping deps ([bbccb12](https://github.com/zkat/cacache/commit/bbccb12))
<a name="9.2.3"></a>
## [9.2.3](https://github.com/zkat/cacache/compare/v9.2.2...v9.2.3) (2017-05-24)
### Bug Fixes
* **rm:** stop crashing if content is missing on rm ([ac90bc0](https://github.com/zkat/cacache/commit/ac90bc0))
<a name="9.2.2"></a>
## [9.2.2](https://github.com/zkat/cacache/compare/v9.2.1...v9.2.2) (2017-05-14)
### Bug Fixes
* **i18n:** lets pretend this didn't happen ([519b4ee](https://github.com/zkat/cacache/commit/519b4ee))
<a name="9.2.1"></a>
## [9.2.1](https://github.com/zkat/cacache/compare/v9.2.0...v9.2.1) (2017-05-14)
### Bug Fixes
* **docs:** fixing translation messup ([bb9e4f9](https://github.com/zkat/cacache/commit/bb9e4f9))
<a name="9.2.0"></a>
# [9.2.0](https://github.com/zkat/cacache/compare/v9.1.0...v9.2.0) (2017-05-14)
### Features
* **i18n:** add Spanish translation for API ([531f9a4](https://github.com/zkat/cacache/commit/531f9a4))
<a name="9.1.0"></a>
# [9.1.0](https://github.com/zkat/cacache/compare/v9.0.0...v9.1.0) (2017-05-14)
### Features
* **i18n:** Add Spanish translation and i18n setup (#91) ([323b90c](https://github.com/zkat/cacache/commit/323b90c))
<a name="9.0.0"></a>
# [9.0.0](https://github.com/zkat/cacache/compare/v8.0.0...v9.0.0) (2017-04-28)
### Bug Fixes
* **memoization:** actually use the LRU ([0e55dc9](https://github.com/zkat/cacache/commit/0e55dc9))
### Features
* **memoization:** memoizers can be injected through opts.memoize (#90) ([e5614c7](https://github.com/zkat/cacache/commit/e5614c7))
### BREAKING CHANGES
* **memoization:** If you were passing an object to opts.memoize, it will now be used as an injected memoization object. If you were only passing booleans and other non-objects through that option, no changes are needed.
<a name="8.0.0"></a>
# [8.0.0](https://github.com/zkat/cacache/compare/v7.1.0...v8.0.0) (2017-04-22)
### Features
* **read:** change hasContent to return {sri, size} (#88) ([bad6c49](https://github.com/zkat/cacache/commit/bad6c49)), closes [#87](https://github.com/zkat/cacache/issues/87)
### BREAKING CHANGES
* **read:** hasContent now returns an object with `{sri, size}` instead of `sri`. Use `result.sri` anywhere that needed the old return value.
<a name="7.1.0"></a>
# [7.1.0](https://github.com/zkat/cacache/compare/v7.0.5...v7.1.0) (2017-04-20)
### Features
* **size:** handle content size info (#49) ([91230af](https://github.com/zkat/cacache/commit/91230af))
<a name="7.0.5"></a>
## [7.0.5](https://github.com/zkat/cacache/compare/v7.0.4...v7.0.5) (2017-04-18)
### Bug Fixes
* **integrity:** new ssri with fixed integrity stream ([6d13e8e](https://github.com/zkat/cacache/commit/6d13e8e))
* **write:** wrap stuff in promises to improve errors ([3624fc5](https://github.com/zkat/cacache/commit/3624fc5))
<a name="7.0.4"></a>
## [7.0.4](https://github.com/zkat/cacache/compare/v7.0.3...v7.0.4) (2017-04-15)
### Bug Fixes
* **fix-owner:** throw away ENOENTs on chownr ([d49bbcd](https://github.com/zkat/cacache/commit/d49bbcd))
<a name="7.0.3"></a>
## [7.0.3](https://github.com/zkat/cacache/compare/v7.0.2...v7.0.3) (2017-04-05)
### Bug Fixes
* **read:** fixing error message for integrity verification failures ([9d4f0a5](https://github.com/zkat/cacache/commit/9d4f0a5))
<a name="7.0.2"></a>
## [7.0.2](https://github.com/zkat/cacache/compare/v7.0.1...v7.0.2) (2017-04-03)
### Bug Fixes
* **integrity:** use EINTEGRITY error code and update ssri ([8dc2e62](https://github.com/zkat/cacache/commit/8dc2e62))
<a name="7.0.1"></a>
## [7.0.1](https://github.com/zkat/cacache/compare/v7.0.0...v7.0.1) (2017-04-03)
### Bug Fixes
* **docs:** fix header name conflict in readme ([afcd456](https://github.com/zkat/cacache/commit/afcd456))
<a name="7.0.0"></a>
# [7.0.0](https://github.com/zkat/cacache/compare/v6.3.0...v7.0.0) (2017-04-03)
### Bug Fixes
* **test:** fix content.write tests when running in docker ([d2e9b6a](https://github.com/zkat/cacache/commit/d2e9b6a))
### Features
* **integrity:** subresource integrity support (#78) ([b1e731f](https://github.com/zkat/cacache/commit/b1e731f))
### BREAKING CHANGES
* **integrity:** The entire API has been overhauled to use SRI hashes instead of digest/hashAlgorithm pairs. SRI hashes follow the Subresource Integrity standard and support strings and objects compatible with [`ssri`](https://npm.im/ssri).
* This change bumps the index version, which will invalidate all previous index entries. Content entries will remain intact, and existing caches will automatically reuse any content from before this breaking change.
* `cacache.get.info()`, `cacache.ls()`, and `cacache.ls.stream()` will now return objects that looks like this:
```
{
key: String,
integrity: '<algorithm>-<base64hash>',
path: ContentPath,
time: Date<ms>,
metadata: Any
}
```
* `opts.digest` and `opts.hashAlgorithm` are obsolete for any API calls that used them.
* Anywhere `opts.digest` was accepted, `opts.integrity` is now an option. Any valid SRI hash is accepted here -- multiple hash entries will be resolved according to the standard: first, the "strongest" hash algorithm will be picked, and then each of the entries for that algorithm will be matched against the content. Content will be validated if *any* of the entries match (so, a single integrity string can be used for multiple "versions" of the same document/data).
* `put.byDigest()`, `put.stream.byDigest`, `get.byDigest()` and `get.stream.byDigest()` now expect an SRI instead of a `digest` + `opts.hashAlgorithm` pairing.
* `get.hasContent()` now expects an integrity hash instead of a digest. If content exists, it will return the specific single integrity hash that was found in the cache.
* `verify()` has learned to handle integrity-based caches, and forgotten how to handle old-style cache indices due to the format change.
* `cacache.rm.content()` now expects an integrity hash instead of a hex digest.
<a name="6.3.0"></a>
# [6.3.0](https://github.com/zkat/cacache/compare/v6.2.0...v6.3.0) (2017-04-01)
### Bug Fixes
* **fixOwner:** ignore EEXIST race condition from mkdirp ([4670e9b](https://github.com/zkat/cacache/commit/4670e9b))
* **index:** ignore index removal races when inserting ([b9d2fa2](https://github.com/zkat/cacache/commit/b9d2fa2))
* **memo:** use lru-cache for better mem management (#75) ([d8ac5aa](https://github.com/zkat/cacache/commit/d8ac5aa))
### Features
* **dependencies:** Switch to move-concurrently (#77) ([dc6482d](https://github.com/zkat/cacache/commit/dc6482d))
<a name="6.2.0"></a>
# [6.2.0](https://github.com/zkat/cacache/compare/v6.1.2...v6.2.0) (2017-03-15)
### Bug Fixes
* **index:** additional bucket entry verification with checksum (#72) ([f8e0f25](https://github.com/zkat/cacache/commit/f8e0f25))
* **verify:** return fixOwner.chownr promise ([6818521](https://github.com/zkat/cacache/commit/6818521))
### Features
* **tmp:** safe tmp dir creation/management util (#73) ([c42da71](https://github.com/zkat/cacache/commit/c42da71))
<a name="6.1.2"></a>
## [6.1.2](https://github.com/zkat/cacache/compare/v6.1.1...v6.1.2) (2017-03-13)
### Bug Fixes
* **index:** set default hashAlgorithm ([d6eb2f0](https://github.com/zkat/cacache/commit/d6eb2f0))
<a name="6.1.1"></a>
## [6.1.1](https://github.com/zkat/cacache/compare/v6.1.0...v6.1.1) (2017-03-13)
### Bug Fixes
* **coverage:** bumping coverage for verify (#71) ([0b7faf6](https://github.com/zkat/cacache/commit/0b7faf6))
* **deps:** glob should have been a regular dep :< ([0640bc4](https://github.com/zkat/cacache/commit/0640bc4))
<a name="6.1.0"></a>
# [6.1.0](https://github.com/zkat/cacache/compare/v6.0.2...v6.1.0) (2017-03-12)
### Bug Fixes
* **coverage:** more coverage for content reads (#70) ([ef4f70a](https://github.com/zkat/cacache/commit/ef4f70a))
* **tests:** use safe-buffer because omfg (#69) ([6ab8132](https://github.com/zkat/cacache/commit/6ab8132))
### Features
* **rm:** limited rm.all and fixed bugs (#66) ([d5d25ba](https://github.com/zkat/cacache/commit/d5d25ba)), closes [#66](https://github.com/zkat/cacache/issues/66)
* **verify:** tested, working cache verifier/gc (#68) ([45ad77a](https://github.com/zkat/cacache/commit/45ad77a))
<a name="6.0.2"></a>
## [6.0.2](https://github.com/zkat/cacache/compare/v6.0.1...v6.0.2) (2017-03-11)
### Bug Fixes
* **index:** segment cache items with another subbucket (#64) ([c3644e5](https://github.com/zkat/cacache/commit/c3644e5))
<a name="6.0.1"></a>
## [6.0.1](https://github.com/zkat/cacache/compare/v6.0.0...v6.0.1) (2017-03-05)
### Bug Fixes
* **docs:** Missed spots in README ([8ffb7fa](https://github.com/zkat/cacache/commit/8ffb7fa))
<a name="6.0.0"></a>
# [6.0.0](https://github.com/zkat/cacache/compare/v5.0.3...v6.0.0) (2017-03-05)
### Bug Fixes
* **api:** keep memo cache mostly-internal ([2f72d0a](https://github.com/zkat/cacache/commit/2f72d0a))
* **content:** use the rest of the string, not the whole string ([fa8f3c3](https://github.com/zkat/cacache/commit/fa8f3c3))
* **deps:** removed `format-number[@2](https://github.com/2).0.2` ([1187791](https://github.com/zkat/cacache/commit/1187791))
* **deps:** removed inflight[@1](https://github.com/1).0.6 ([0d1819c](https://github.com/zkat/cacache/commit/0d1819c))
* **deps:** rimraf[@2](https://github.com/2).6.1 ([9efab6b](https://github.com/zkat/cacache/commit/9efab6b))
* **deps:** standard[@9](https://github.com/9).0.0 ([4202cba](https://github.com/zkat/cacache/commit/4202cba))
* **deps:** tap[@10](https://github.com/10).3.0 ([aa03088](https://github.com/zkat/cacache/commit/aa03088))
* **deps:** weallcontribute[@1](https://github.com/1).0.8 ([ad4f4dc](https://github.com/zkat/cacache/commit/ad4f4dc))
* **docs:** add security note to hashKey ([03f81ba](https://github.com/zkat/cacache/commit/03f81ba))
* **hashes:** change default hashAlgorithm to sha512 ([ea00ba6](https://github.com/zkat/cacache/commit/ea00ba6))
* **hashes:** missed a spot for hashAlgorithm defaults ([45997d8](https://github.com/zkat/cacache/commit/45997d8))
* **index:** add length header before JSON for verification ([fb8cb4d](https://github.com/zkat/cacache/commit/fb8cb4d))
* **index:** change index filenames to sha1s of keys ([bbc5fca](https://github.com/zkat/cacache/commit/bbc5fca))
* **index:** who cares about race conditions anyway ([b1d3888](https://github.com/zkat/cacache/commit/b1d3888))
* **perf:** bulk-read get+read for massive speed ([d26cdf9](https://github.com/zkat/cacache/commit/d26cdf9))
* **perf:** use bulk file reads for index reads ([79a8891](https://github.com/zkat/cacache/commit/79a8891))
* **put-stream:** remove tmp file on stream insert error ([65f6632](https://github.com/zkat/cacache/commit/65f6632))
* **put-stream:** robustified and predictibilized ([daf9e08](https://github.com/zkat/cacache/commit/daf9e08))
* **put-stream:** use new promise API for moves ([1d36013](https://github.com/zkat/cacache/commit/1d36013))
* **readme:** updated to reflect new default hashAlgo ([c60a2fa](https://github.com/zkat/cacache/commit/c60a2fa))
* **verify:** tiny typo fix ([db22d05](https://github.com/zkat/cacache/commit/db22d05))
### Features
* **api:** converted external api ([7bf032f](https://github.com/zkat/cacache/commit/7bf032f))
* **cacache:** exported clearMemoized() utility ([8d2c5b6](https://github.com/zkat/cacache/commit/8d2c5b6))
* **cache:** add versioning to content and index ([31bc549](https://github.com/zkat/cacache/commit/31bc549))
* **content:** collate content files into subdirs ([c094d9f](https://github.com/zkat/cacache/commit/c094d9f))
* **deps:** [@npmcorp](https://github.com/npmcorp)/move[@1](https://github.com/1).0.0 ([bdd00bf](https://github.com/zkat/cacache/commit/bdd00bf))
* **deps:** bluebird[@3](https://github.com/3).4.7 ([3a17aff](https://github.com/zkat/cacache/commit/3a17aff))
* **deps:** promise-inflight[@1](https://github.com/1).0.1 ([a004fe6](https://github.com/zkat/cacache/commit/a004fe6))
* **get:** added memoization support for get ([c77d794](https://github.com/zkat/cacache/commit/c77d794))
* **get:** export hasContent ([2956ec3](https://github.com/zkat/cacache/commit/2956ec3))
* **index:** add hashAlgorithm and format insert ret val ([b639746](https://github.com/zkat/cacache/commit/b639746))
* **index:** collate index files into subdirs ([e8402a5](https://github.com/zkat/cacache/commit/e8402a5))
* **index:** promisify entry index ([cda3335](https://github.com/zkat/cacache/commit/cda3335))
* **memo:** added memoization lib ([da07b92](https://github.com/zkat/cacache/commit/da07b92))
* **memo:** export memoization api ([954b1b3](https://github.com/zkat/cacache/commit/954b1b3))
* **move-file:** add move fallback for weird errors ([5cf4616](https://github.com/zkat/cacache/commit/5cf4616))
* **perf:** bulk content write api ([51b536e](https://github.com/zkat/cacache/commit/51b536e))
* **put:** added memoization support to put ([b613a70](https://github.com/zkat/cacache/commit/b613a70))
* **read:** switched to promises ([a869362](https://github.com/zkat/cacache/commit/a869362))
* **rm:** added memoization support to rm ([4205cf0](https://github.com/zkat/cacache/commit/4205cf0))
* **rm:** switched to promises ([a000d24](https://github.com/zkat/cacache/commit/a000d24))
* **util:** promise-inflight ownership fix requests ([9517cd7](https://github.com/zkat/cacache/commit/9517cd7))
* **util:** use promises for api ([ae204bb](https://github.com/zkat/cacache/commit/ae204bb))
* **verify:** converted to Promises ([f0b3974](https://github.com/zkat/cacache/commit/f0b3974))
### BREAKING CHANGES
* cache: index/content directories are now versioned. Previous caches are no longer compatible and cannot be migrated.
* util: fix-owner now uses Promises instead of callbacks
* index: Previously-generated index entries are no longer compatible and the index must be regenerated.
* index: The index format has changed and previous caches are no longer compatible. Existing caches will need to be regenerated.
* hashes: Default hashAlgorithm changed from sha1 to sha512. If you
rely on the prior setting, pass `opts.hashAlgorithm` in explicitly.
* content: Previously-generated content directories are no longer compatible
and must be regenerated.
* verify: API is now promise-based
* read: Switches to a Promise-based API and removes callback stuff
* rm: Switches to a Promise-based API and removes callback stuff
* index: this changes the API to work off promises instead of callbacks
* api: this means we are going all in on promises now
+16
View File
@@ -0,0 +1,16 @@
ISC License
Copyright (c) npm, Inc.
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE COPYRIGHT HOLDER DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
USE OR PERFORMANCE OF THIS SOFTWARE.
+628
View File
@@ -0,0 +1,628 @@
# cacache [![npm version](https://img.shields.io/npm/v/cacache.svg)](https://npm.im/cacache) [![license](https://img.shields.io/npm/l/cacache.svg)](https://npm.im/cacache) [![Travis](https://img.shields.io/travis/zkat/cacache.svg)](https://travis-ci.org/zkat/cacache) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/zkat/cacache?svg=true)](https://ci.appveyor.com/project/zkat/cacache) [![Coverage Status](https://coveralls.io/repos/github/zkat/cacache/badge.svg?branch=latest)](https://coveralls.io/github/zkat/cacache?branch=latest)
[`cacache`](https://github.com/zkat/cacache) es una librería de Node.js para
manejar caches locales en disco, con acceso tanto con claves únicas como
direcciones de contenido (hashes/hacheos). Es súper rápida, excelente con el
acceso concurrente, y jamás te dará datos incorrectos, aún si se corrompen o
manipulan directamente los ficheros del cache.
El propósito original era reemplazar el caché local de
[npm](https://npm.im/npm), pero se puede usar por su propia cuenta.
_Traducciones: [English](README.md)_
## Instalación
`$ npm install --save cacache`
## Índice
* [Ejemplo](#ejemplo)
* [Características](#características)
* [Cómo Contribuir](#cómo-contribuir)
* [API](#api)
* [Usando el API en español](#localized-api)
* Leer
* [`ls`](#ls)
* [`ls.flujo`](#ls-stream)
* [`saca`](#get-data)
* [`saca.flujo`](#get-stream)
* [`saca.info`](#get-info)
* [`saca.tieneDatos`](#get-hasContent)
* Escribir
* [`mete`](#put-data)
* [`mete.flujo`](#put-stream)
* [opciones para `mete*`](#put-options)
* [`rm.todo`](#rm-all)
* [`rm.entrada`](#rm-entry)
* [`rm.datos`](#rm-content)
* Utilidades
* [`ponLenguaje`](#set-locale)
* [`limpiaMemoizado`](#clear-memoized)
* [`tmp.hazdir`](#tmp-mkdir)
* [`tmp.conTmp`](#with-tmp)
* Integridad
* [Subresource Integrity](#integrity)
* [`verifica`](#verify)
* [`verifica.ultimaVez`](#verify-last-run)
### Ejemplo
```javascript
const cacache = require('cacache/es')
const fs = require('fs')
const tarbol = '/ruta/a/mi-tar.tgz'
const rutaCache = '/tmp/my-toy-cache'
const clave = 'mi-clave-única-1234'
// ¡Añádelo al caché! Usa `rutaCache` como raíz del caché.
cacache.mete(rutaCache, clave, '10293801983029384').then(integrity => {
console.log(`Saved content to ${rutaCache}.`)
})
const destino = '/tmp/mytar.tgz'
// Copia el contenido del caché a otro fichero, pero esta vez con flujos.
cacache.saca.flujo(
rutaCache, clave
).pipe(
fs.createWriteStream(destino)
).on('finish', () => {
console.log('extracción completada')
})
// La misma cosa, pero accesando el contenido directamente, sin tocar el índice.
cacache.saca.porHacheo(rutaCache, integridad).then(datos => {
fs.writeFile(destino, datos, err => {
console.log('datos del tarbol sacados basado en su sha512, y escrito a otro fichero')
})
})
```
### Características
* Extracción por clave o por dirección de contenido (shasum, etc)
* Usa el estándard de web, [Subresource Integrity](#integrity)
* Compatible con multiples algoritmos - usa sha1, sha512, etc, en el mismo caché sin problema
* Entradas con contenido idéntico comparten ficheros
* Tolerancia de fallas (inmune a corrupción, ficheros parciales, carreras de proceso, etc)
* Verificación completa de datos cuando (escribiendo y leyendo)
* Concurrencia rápida, segura y "lockless"
* Compatible con `stream`s (flujos)
* Compatible con `Promise`s (promesas)
* Bastante rápida -- acceso, incluyendo verificación, en microsegundos
* Almacenaje de metadatos arbitrarios
* Colección de basura y verificación adicional fuera de banda
* Cobertura rigurosa de pruebas
* Probablente hay un "Bloom filter" por ahí en algún lado. Eso le mola a la gente, ¿Verdad? 🤔
### Cómo Contribuir
El equipo de cacache felizmente acepta contribuciones de código y otras maneras de participación. ¡Hay muchas formas diferentes de contribuir! La [Guía de Colaboradores](CONTRIBUTING.md) (en inglés) tiene toda la información que necesitas para cualquier tipo de contribución: todo desde cómo reportar errores hasta cómo someter parches con nuevas características. Con todo y eso, no se preocupe por si lo que haces está exáctamente correcto: no hay ningún problema en hacer preguntas si algo no está claro, o no lo encuentras.
El equipo de cacache tiene miembros hispanohablantes: es completamente aceptable crear `issues` y `pull requests` en español/castellano.
Todos los participantes en este proyecto deben obedecer el [Código de Conducta](CODE_OF_CONDUCT.md) (en inglés), y en general actuar de forma amable y respetuosa mientras participan en esta comunidad.
Por favor refiérase al [Historial de Cambios](CHANGELOG.md) (en inglés) para detalles sobre cambios importantes incluídos en cada versión.
Finalmente, cacache tiene un sistema de localización de lenguaje. Si te interesa añadir lenguajes o mejorar los que existen, mira en el directorio `./locales` para comenzar.
Happy hacking!
### API
#### <a name="localized-api"></a> Usando el API en español
cacache incluye una traducción completa de su API al castellano, con las mismas
características. Para usar el API como está documentado en este documento, usa
`require('cacache/es')`
cacache también tiene otros lenguajes: encuéntralos bajo `./locales`, y podrás
usar el API en ese lenguaje con `require('cacache/<lenguaje>')`
#### <a name="ls"></a> `> cacache.ls(cache) -> Promise<Object>`
Enumera todas las entradas en el caché, dentro de un solo objeto. Cada entrada
en el objeto tendrá como clave la clave única usada para el índice, el valor
siendo un objeto de [`saca.info`](#get-info).
##### Ejemplo
```javascript
cacache.ls(rutaCache).then(console.log)
// Salida
{
'my-thing': {
key: 'my-thing',
integrity: 'sha512-BaSe64/EnCoDED+HAsh=='
path: '.testcache/content/deadbeef', // unido con `rutaCache`
time: 12345698490,
size: 4023948,
metadata: {
name: 'blah',
version: '1.2.3',
description: 'this was once a package but now it is my-thing'
}
},
'other-thing': {
key: 'other-thing',
integrity: 'sha1-ANothER+hasH=',
path: '.testcache/content/bada55',
time: 11992309289,
size: 111112
}
}
```
#### <a name="ls-stream"></a> `> cacache.ls.flujo(cache) -> Readable`
Enumera todas las entradas en el caché, emitiendo un objeto de
[`saca.info`](#get-info) por cada evento de `data` en el flujo.
##### Ejemplo
```javascript
cacache.ls.flujo(rutaCache).on('data', console.log)
// Salida
{
key: 'my-thing',
integrity: 'sha512-BaSe64HaSh',
path: '.testcache/content/deadbeef', // unido con `rutaCache`
time: 12345698490,
size: 13423,
metadata: {
name: 'blah',
version: '1.2.3',
description: 'this was once a package but now it is my-thing'
}
}
{
key: 'other-thing',
integrity: 'whirlpool-WoWSoMuchSupport',
path: '.testcache/content/bada55',
time: 11992309289,
size: 498023984029
}
{
...
}
```
#### <a name="get-data"></a> `> cacache.saca(cache, clave, [ops]) -> Promise({data, metadata, integrity})`
Devuelve un objeto con los datos, hacheo de integridad y metadatos identificados
por la `clave`. La propiedad `data` de este objeto será una instancia de
`Buffer` con los datos almacenados en el caché. to do with it! cacache just
won't care.
`integrity` es un `string` de [Subresource Integrity](#integrity). Dígase, un
`string` que puede ser usado para verificar a la `data`, que tiene como formato
`<algoritmo>-<hacheo-integridad-base64>`.
So no existe ninguna entrada identificada por `clave`, o se los datos
almacenados localmente fallan verificación, el `Promise` fallará.
Una sub-función, `saca.porHacheo`, tiene casi el mismo comportamiento, excepto
que busca entradas usando el hacheo de integridad, sin tocar el índice general.
Esta versión *sólo* devuelve `data`, sin ningún objeto conteniéndola.
##### Nota
Esta función lee la entrada completa a la memoria antes de devolverla. Si estás
almacenando datos Muy Grandes, es posible que [`saca.flujo`](#get-stream) sea
una mejor solución.
##### Ejemplo
```javascript
// Busca por clave
cache.saca(rutaCache, 'my-thing').then(console.log)
// Salida:
{
metadata: {
thingName: 'my'
},
integrity: 'sha512-BaSe64HaSh',
data: Buffer#<deadbeef>,
size: 9320
}
// Busca por hacheo
cache.saca.porHacheo(rutaCache, 'sha512-BaSe64HaSh').then(console.log)
// Salida:
Buffer#<deadbeef>
```
#### <a name="get-stream"></a> `> cacache.saca.flujo(cache, clave, [ops]) -> Readable`
Devuelve un [Readable
Stream](https://nodejs.org/api/stream.html#stream_readable_streams) de los datos
almacenados bajo `clave`.
So no existe ninguna entrada identificada por `clave`, o se los datos
almacenados localmente fallan verificación, el `Promise` fallará.
`metadata` y `integrity` serán emitidos como eventos antes de que el flujo
cierre.
Una sub-función, `saca.flujo.porHacheo`, tiene casi el mismo comportamiento,
excepto que busca entradas usando el hacheo de integridad, sin tocar el índice
general. Esta versión no emite eventos de `metadata` o `integrity`.
##### Ejemplo
```javascript
// Busca por clave
cache.saca.flujo(
rutaCache, 'my-thing'
).on('metadata', metadata => {
console.log('metadata:', metadata)
}).on('integrity', integrity => {
console.log('integrity:', integrity)
}).pipe(
fs.createWriteStream('./x.tgz')
)
// Salidas:
metadata: { ... }
integrity: 'sha512-SoMeDIGest+64=='
// Busca por hacheo
cache.saca.flujo.porHacheo(
rutaCache, 'sha512-SoMeDIGest+64=='
).pipe(
fs.createWriteStream('./x.tgz')
)
```
#### <a name="get-info"></a> `> cacache.saca.info(cache, clave) -> Promise`
Busca la `clave` en el índice del caché, devolviendo información sobre la
entrada si existe.
##### Campos
* `key` - Clave de la entrada. Igual al argumento `clave`.
* `integrity` - [hacheo de Subresource Integrity](#integrity) del contenido al que se refiere esta entrada.
* `path` - Dirección del fichero de datos almacenados, relativa al argumento `cache`.
* `time` - Hora de creación de la entrada
* `metadata` - Metadatos asignados a esta entrada por el usuario
##### Ejemplo
```javascript
cacache.saca.info(rutaCache, 'my-thing').then(console.log)
// Salida
{
key: 'my-thing',
integrity: 'sha256-MUSTVERIFY+ALL/THINGS=='
path: '.testcache/content/deadbeef',
time: 12345698490,
size: 849234,
metadata: {
name: 'blah',
version: '1.2.3',
description: 'this was once a package but now it is my-thing'
}
}
```
#### <a name="get-hasContent"></a> `> cacache.saca.tieneDatos(cache, integrity) -> Promise`
Busca un [hacheo Subresource Integrity](#integrity) en el caché. Si existe el
contenido asociado con `integrity`, devuelve un objeto con dos campos: el hacheo
_específico_ que se usó para la búsqueda, `sri`, y el tamaño total del
contenido, `size`. Si no existe ningún contenido asociado con `integrity`,
devuelve `false`.
##### Ejemplo
```javascript
cacache.saca.tieneDatos(rutaCache, 'sha256-MUSTVERIFY+ALL/THINGS==').then(console.log)
// Salida
{
sri: {
source: 'sha256-MUSTVERIFY+ALL/THINGS==',
algorithm: 'sha256',
digest: 'MUSTVERIFY+ALL/THINGS==',
options: []
},
size: 9001
}
cacache.saca.tieneDatos(rutaCache, 'sha521-NOT+IN/CACHE==').then(console.log)
// Salida
false
```
#### <a name="put-data"></a> `> cacache.mete(cache, clave, datos, [ops]) -> Promise`
Inserta `datos` en el caché. El `Promise` devuelto se resuelve con un hacheo
(generado conforme a [`ops.algorithms`](#optsalgorithms)) después que la entrada
haya sido escrita en completo.
##### Ejemplo
```javascript
fetch(
'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
).then(datos => {
return cacache.mete(rutaCache, 'registry.npmjs.org|cacache@1.0.0', datos)
}).then(integridad => {
console.log('el hacheo de integridad es', integridad)
})
```
#### <a name="put-stream"></a> `> cacache.mete.flujo(cache, clave, [ops]) -> Writable`
Devuelve un [Writable
Stream](https://nodejs.org/api/stream.html#stream_writable_streams) que inserta
al caché los datos escritos a él. Emite un evento `integrity` con el hacheo del
contenido escrito, cuando completa.
##### Ejemplo
```javascript
request.get(
'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
).pipe(
cacache.mete.flujo(
rutaCache, 'registry.npmjs.org|cacache@1.0.0'
).on('integrity', d => console.log(`integrity digest is ${d}`))
)
```
#### <a name="put-options"></a> `> opciones para cacache.mete`
La funciones `cacache.mete` tienen un número de opciones en común.
##### `ops.metadata`
Metadatos del usuario que se almacenarán con la entrada.
##### `ops.size`
El tamaño declarado de los datos que se van a insertar. Si es proveído, cacache
verificará que los datos escritos sean de ese tamaño, o si no, fallará con un
error con código `EBADSIZE`.
##### `ops.integrity`
El hacheo de integridad de los datos siendo escritos.
Si es proveído, y los datos escritos no le corresponden, la operación fallará
con un error con código `EINTEGRITY`.
`ops.algorithms` no tiene ningún efecto si esta opción está presente.
##### `ops.algorithms`
Por Defecto: `['sha512']`
Algoritmos que se deben usar cuando se calcule el hacheo de [subresource
integrity](#integrity) para los datos insertados. Puede usar cualquier algoritmo
enumerado en `crypto.getHashes()`.
Por el momento, sólo se acepta un algoritmo (dígase, un array con exáctamente un
valor). No tiene ningún efecto si `ops.integrity` también ha sido proveido.
##### `ops.uid`/`ops.gid`
Si están presentes, cacache hará todo lo posible para asegurarse que todos los
ficheros creados en el proceso de sus operaciones en el caché usen esta
combinación en particular.
##### `ops.memoize`
Por Defecto: `null`
Si es verdad, cacache tratará de memoizar los datos de la entrada en memoria. La
próxima vez que el proceso corriente trate de accesar los datos o entrada,
cacache buscará en memoria antes de buscar en disco.
Si `ops.memoize` es un objeto regular o un objeto como `Map` (es decir, un
objeto con métodos `get()` y `set()`), este objeto en sí sera usado en vez del
caché de memoria global. Esto permite tener lógica específica a tu aplicación
encuanto al almacenaje en memoria de tus datos.
Si quieres asegurarte que los datos se lean del disco en vez de memoria, usa
`memoize: false` cuando uses funciones de `cacache.saca`.
#### <a name="rm-all"></a> `> cacache.rm.todo(cache) -> Promise`
Borra el caché completo, incluyendo ficheros temporeros, ficheros de datos, y el
índice del caché.
##### Ejemplo
```javascript
cacache.rm.todo(rutaCache).then(() => {
console.log('THE APOCALYPSE IS UPON US 😱')
})
```
#### <a name="rm-entry"></a> `> cacache.rm.entrada(cache, clave) -> Promise`
Alias: `cacache.rm`
Borra la entrada `clave` del índuce. El contenido asociado con esta entrada
seguirá siendo accesible por hacheo usando
[`saca.flujo.porHacheo`](#get-stream).
Para borrar el contenido en sí, usa [`rm.datos`](#rm-content). Si quieres hacer
esto de manera más segura (pues ficheros de contenido pueden ser usados por
multiples entradas), usa [`verifica`](#verify) para borrar huérfanos.
##### Ejemplo
```javascript
cacache.rm.entrada(rutaCache, 'my-thing').then(() => {
console.log('I did not like it anyway')
})
```
#### <a name="rm-content"></a> `> cacache.rm.datos(cache, integrity) -> Promise`
Borra el contenido identificado por `integrity`. Cualquier entrada que se
refiera a este contenido quedarán huérfanas y se invalidarán si se tratan de
accesar, al menos que contenido idéntico sea añadido bajo `integrity`.
##### Ejemplo
```javascript
cacache.rm.datos(rutaCache, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => {
console.log('los datos para `mi-cosa` se borraron')
})
```
#### <a name="set-locale"></a> `> cacache.ponLenguaje(locale)`
Configura el lenguaje usado para mensajes y errores de cacache. La lista de
lenguajes disponibles está en el directorio `./locales` del proyecto.
_Te interesa añadir más lenguajes? [Somete un PR](CONTRIBUTING.md)!_
#### <a name="clear-memoized"></a> `> cacache.limpiaMemoizado()`
Completamente reinicializa el caché de memoria interno. Si estás usando tu
propio objecto con `ops.memoize`, debes hacer esto de manera específica a él.
#### <a name="tmp-mkdir"></a> `> tmp.hazdir(cache, ops) -> Promise<Path>`
Alias: `tmp.mkdir`
Devuelve un directorio único dentro del directorio `tmp` del caché.
Una vez tengas el directorio, es responsabilidad tuya asegurarte que todos los
ficheros escrito a él sean creados usando los permisos y `uid`/`gid` concordante
con el caché. Si no, puedes pedirle a cacache que lo haga llamando a
[`cacache.tmp.fix()`](#tmp-fix). Esta función arreglará todos los permisos en el
directorio tmp.
Si quieres que cacache limpie el directorio automáticamente cuando termines, usa
[`cacache.tmp.conTmp()`](#with-tpm).
##### Ejemplo
```javascript
cacache.tmp.mkdir(cache).then(dir => {
fs.writeFile(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
})
```
#### <a name="with-tmp"></a> `> tmp.conTmp(cache, ops, cb) -> Promise`
Crea un directorio temporero con [`tmp.mkdir()`](#tmp-mkdir) y ejecuta `cb` con
él como primer argumento. El directorio creado será removido automáticamente
cuando el valor devolvido por `cb()` se resuelva.
Las mismas advertencias aplican en cuanto a manejando permisos para los ficheros
dentro del directorio.
##### Ejemplo
```javascript
cacache.tmp.conTmp(cache, dir => {
return fs.writeFileAsync(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
}).then(() => {
// `dir` no longer exists
})
```
#### <a name="integrity"></a> Hacheos de Subresource Integrity
cacache usa strings que siguen la especificación de [Subresource Integrity
spec](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
Es decir, donde quiera cacache espera un argumento o opción `integrity`, ese
string debería usar el formato `<algoritmo>-<hacheo-base64>`.
Una variación importante sobre los hacheos que cacache acepta es que acepta el
nombre de cualquier algoritmo aceptado por el proceso de Node.js donde se usa.
Puedes usar `crypto.getHashes()` para ver cuales están disponibles.
##### Generando tus propios hacheos
Si tienes un `shasum`, en general va a estar en formato de string hexadecimal
(es decir, un `sha1` se vería como algo así:
`5f5513f8822fdbe5145af33b64d8d970dcf95c6e`).
Para ser compatible con cacache, necesitas convertir esto a su equivalente en
subresource integrity. Por ejemplo, el hacheo correspondiente al ejemplo
anterior sería: `sha1-X1UT+IIv2+UUWvM7ZNjZcNz5XG4=`.
Puedes usar código así para generarlo por tu cuenta:
```javascript
const crypto = require('crypto')
const algoritmo = 'sha512'
const datos = 'foobarbaz'
const integrity = (
algorithm +
'-' +
crypto.createHash(algoritmo).update(datos).digest('base64')
)
```
También puedes usar [`ssri`](https://npm.im/ssri) para deferir el trabajo a otra
librería que garantiza que todo esté correcto, pues maneja probablemente todas
las operaciones que tendrías que hacer con SRIs, incluyendo convirtiendo entre
hexadecimal y el formato SRI.
#### <a name="verify"></a> `> cacache.verifica(cache, ops) -> Promise`
Examina y arregla tu caché:
* Limpia entradas inválidas, huérfanas y corrompidas
* Te deja filtrar cuales entradas retener, con tu propio filtro
* Reclama cualquier ficheros de contenido sin referencias en el índice
* Verifica integridad de todos los ficheros de contenido y remueve los malos
* Arregla permisos del caché
* Remieve el directorio `tmp` en el caché, y todo su contenido.
Cuando termine, devuelve un objeto con varias estadísticas sobre el proceso de
verificación, por ejemplo la cantidad de espacio de disco reclamado, el número
de entradas válidas, número de entradas removidas, etc.
##### Opciones
* `ops.uid` - uid para asignarle al caché y su contenido
* `ops.gid` - gid para asignarle al caché y su contenido
* `ops.filter` - recibe una entrada como argumento. Devuelve falso para removerla. Nota: es posible que esta función sea invocada con la misma entrada más de una vez.
##### Example
```sh
echo somegarbage >> $RUTACACHE/content/deadbeef
```
```javascript
cacache.verifica(rutaCache).then(stats => {
// deadbeef collected, because of invalid checksum.
console.log('cache is much nicer now! stats:', stats)
})
```
#### <a name="verify-last-run"></a> `> cacache.verifica.ultimaVez(cache) -> Promise`
Alias: `últimaVez`
Devuelve un `Date` que representa la última vez que `cacache.verifica` fue
ejecutada en `cache`.
##### Example
```javascript
cacache.verifica(rutaCache).then(() => {
cacache.verifica.ultimaVez(rutaCache).then(última => {
console.log('La última vez que se usó cacache.verifica() fue ' + última)
})
})
```
+624
View File
@@ -0,0 +1,624 @@
# cacache [![npm version](https://img.shields.io/npm/v/cacache.svg)](https://npm.im/cacache) [![license](https://img.shields.io/npm/l/cacache.svg)](https://npm.im/cacache) [![Travis](https://img.shields.io/travis/zkat/cacache.svg)](https://travis-ci.org/zkat/cacache) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/zkat/cacache?svg=true)](https://ci.appveyor.com/project/zkat/cacache) [![Coverage Status](https://coveralls.io/repos/github/zkat/cacache/badge.svg?branch=latest)](https://coveralls.io/github/zkat/cacache?branch=latest)
[`cacache`](https://github.com/zkat/cacache) is a Node.js library for managing
local key and content address caches. It's really fast, really good at
concurrency, and it will never give you corrupted data, even if cache files
get corrupted or manipulated.
It was originally written to be used as [npm](https://npm.im)'s local cache, but
can just as easily be used on its own.
_Translations: [español](README.es.md)_
## Install
`$ npm install --save cacache`
## Table of Contents
* [Example](#example)
* [Features](#features)
* [Contributing](#contributing)
* [API](#api)
* [Using localized APIs](#localized-api)
* Reading
* [`ls`](#ls)
* [`ls.stream`](#ls-stream)
* [`get`](#get-data)
* [`get.stream`](#get-stream)
* [`get.info`](#get-info)
* [`get.hasContent`](#get-hasContent)
* Writing
* [`put`](#put-data)
* [`put.stream`](#put-stream)
* [`put*` opts](#put-options)
* [`rm.all`](#rm-all)
* [`rm.entry`](#rm-entry)
* [`rm.content`](#rm-content)
* Utilities
* [`setLocale`](#set-locale)
* [`clearMemoized`](#clear-memoized)
* [`tmp.mkdir`](#tmp-mkdir)
* [`tmp.withTmp`](#with-tmp)
* Integrity
* [Subresource Integrity](#integrity)
* [`verify`](#verify)
* [`verify.lastRun`](#verify-last-run)
### Example
```javascript
const cacache = require('cacache/en')
const fs = require('fs')
const tarball = '/path/to/mytar.tgz'
const cachePath = '/tmp/my-toy-cache'
const key = 'my-unique-key-1234'
// Cache it! Use `cachePath` as the root of the content cache
cacache.put(cachePath, key, '10293801983029384').then(integrity => {
console.log(`Saved content to ${cachePath}.`)
})
const destination = '/tmp/mytar.tgz'
// Copy the contents out of the cache and into their destination!
// But this time, use stream instead!
cacache.get.stream(
cachePath, key
).pipe(
fs.createWriteStream(destination)
).on('finish', () => {
console.log('done extracting!')
})
// The same thing, but skip the key index.
cacache.get.byDigest(cachePath, integrityHash).then(data => {
fs.writeFile(destination, data, err => {
console.log('tarball data fetched based on its sha512sum and written out!')
})
})
```
### Features
* Extraction by key or by content address (shasum, etc)
* [Subresource Integrity](#integrity) web standard support
* Multi-hash support - safely host sha1, sha512, etc, in a single cache
* Automatic content deduplication
* Fault tolerance (immune to corruption, partial writes, process races, etc)
* Consistency guarantees on read and write (full data verification)
* Lockless, high-concurrency cache access
* Streaming support
* Promise support
* Pretty darn fast -- sub-millisecond reads and writes including verification
* Arbitrary metadata storage
* Garbage collection and additional offline verification
* Thorough test coverage
* There's probably a bloom filter in there somewhere. Those are cool, right? 🤔
### Contributing
The cacache team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! The [Contributor Guide](CONTRIBUTING.md) has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.
All participants and maintainers in this project are expected to follow [Code of Conduct](CODE_OF_CONDUCT.md), and just generally be excellent to each other.
Please refer to the [Changelog](CHANGELOG.md) for project history details, too.
Happy hacking!
### API
#### <a name="localized-api"></a> Using localized APIs
cacache includes a complete API in English, with the same features as other
translations. To use the English API as documented in this README, use
`require('cacache/en')`. This is also currently the default if you do
`require('cacache')`, but may change in the future.
cacache also supports other languages! You can find the list of currently
supported ones by looking in `./locales` in the source directory. You can use
the API in that language with `require('cacache/<lang>')`.
Want to add support for a new language? Please go ahead! You should be able to
copy `./locales/en.js` and `./locales/en.json` and fill them in. Translating the
`README.md` is a bit more work, but also appreciated if you get around to it. 👍🏼
#### <a name="ls"></a> `> cacache.ls(cache) -> Promise<Object>`
Lists info for all entries currently in the cache as a single large object. Each
entry in the object will be keyed by the unique index key, with corresponding
[`get.info`](#get-info) objects as the values.
##### Example
```javascript
cacache.ls(cachePath).then(console.log)
// Output
{
'my-thing': {
key: 'my-thing',
integrity: 'sha512-BaSe64/EnCoDED+HAsh=='
path: '.testcache/content/deadbeef', // joined with `cachePath`
time: 12345698490,
size: 4023948,
metadata: {
name: 'blah',
version: '1.2.3',
description: 'this was once a package but now it is my-thing'
}
},
'other-thing': {
key: 'other-thing',
integrity: 'sha1-ANothER+hasH=',
path: '.testcache/content/bada55',
time: 11992309289,
size: 111112
}
}
```
#### <a name="ls-stream"></a> `> cacache.ls.stream(cache) -> Readable`
Lists info for all entries currently in the cache as a single large object.
This works just like [`ls`](#ls), except [`get.info`](#get-info) entries are
returned as `'data'` events on the returned stream.
##### Example
```javascript
cacache.ls.stream(cachePath).on('data', console.log)
// Output
{
key: 'my-thing',
integrity: 'sha512-BaSe64HaSh',
path: '.testcache/content/deadbeef', // joined with `cachePath`
time: 12345698490,
size: 13423,
metadata: {
name: 'blah',
version: '1.2.3',
description: 'this was once a package but now it is my-thing'
}
}
{
key: 'other-thing',
integrity: 'whirlpool-WoWSoMuchSupport',
path: '.testcache/content/bada55',
time: 11992309289,
size: 498023984029
}
{
...
}
```
#### <a name="get-data"></a> `> cacache.get(cache, key, [opts]) -> Promise({data, metadata, integrity})`
Returns an object with the cached data, digest, and metadata identified by
`key`. The `data` property of this object will be a `Buffer` instance that
presumably holds some data that means something to you. I'm sure you know what
to do with it! cacache just won't care.
`integrity` is a [Subresource
Integrity](#integrity)
string. That is, a string that can be used to verify `data`, which looks like
`<hash-algorithm>-<base64-integrity-hash>`.
If there is no content identified by `key`, or if the locally-stored data does
not pass the validity checksum, the promise will be rejected.
A sub-function, `get.byDigest` may be used for identical behavior, except lookup
will happen by integrity hash, bypassing the index entirely. This version of the
function *only* returns `data` itself, without any wrapper.
##### Note
This function loads the entire cache entry into memory before returning it. If
you're dealing with Very Large data, consider using [`get.stream`](#get-stream)
instead.
##### Example
```javascript
// Look up by key
cache.get(cachePath, 'my-thing').then(console.log)
// Output:
{
metadata: {
thingName: 'my'
},
integrity: 'sha512-BaSe64HaSh',
data: Buffer#<deadbeef>,
size: 9320
}
// Look up by digest
cache.get.byDigest(cachePath, 'sha512-BaSe64HaSh').then(console.log)
// Output:
Buffer#<deadbeef>
```
#### <a name="get-stream"></a> `> cacache.get.stream(cache, key, [opts]) -> Readable`
Returns a [Readable Stream](https://nodejs.org/api/stream.html#stream_readable_streams) of the cached data identified by `key`.
If there is no content identified by `key`, or if the locally-stored data does
not pass the validity checksum, an error will be emitted.
`metadata` and `integrity` events will be emitted before the stream closes, if
you need to collect that extra data about the cached entry.
A sub-function, `get.stream.byDigest` may be used for identical behavior,
except lookup will happen by integrity hash, bypassing the index entirely. This
version does not emit the `metadata` and `integrity` events at all.
##### Example
```javascript
// Look up by key
cache.get.stream(
cachePath, 'my-thing'
).on('metadata', metadata => {
console.log('metadata:', metadata)
}).on('integrity', integrity => {
console.log('integrity:', integrity)
}).pipe(
fs.createWriteStream('./x.tgz')
)
// Outputs:
metadata: { ... }
integrity: 'sha512-SoMeDIGest+64=='
// Look up by digest
cache.get.stream.byDigest(
cachePath, 'sha512-SoMeDIGest+64=='
).pipe(
fs.createWriteStream('./x.tgz')
)
```
#### <a name="get-info"></a> `> cacache.get.info(cache, key) -> Promise`
Looks up `key` in the cache index, returning information about the entry if
one exists.
##### Fields
* `key` - Key the entry was looked up under. Matches the `key` argument.
* `integrity` - [Subresource Integrity hash](#integrity) for the content this entry refers to.
* `path` - Filesystem path relative to `cache` argument where content is stored.
* `time` - Timestamp the entry was first added on.
* `metadata` - User-assigned metadata associated with the entry/content.
##### Example
```javascript
cacache.get.info(cachePath, 'my-thing').then(console.log)
// Output
{
key: 'my-thing',
integrity: 'sha256-MUSTVERIFY+ALL/THINGS=='
path: '.testcache/content/deadbeef',
time: 12345698490,
size: 849234,
metadata: {
name: 'blah',
version: '1.2.3',
description: 'this was once a package but now it is my-thing'
}
}
```
#### <a name="get-hasContent"></a> `> cacache.get.hasContent(cache, integrity) -> Promise`
Looks up a [Subresource Integrity hash](#integrity) in the cache. If content
exists for this `integrity`, it will return an object, with the specific single integrity hash
that was found in `sri` key, and the size of the found content as `size`. If no content exists for this integrity, it will return `false`.
##### Example
```javascript
cacache.get.hasContent(cachePath, 'sha256-MUSTVERIFY+ALL/THINGS==').then(console.log)
// Output
{
sri: {
source: 'sha256-MUSTVERIFY+ALL/THINGS==',
algorithm: 'sha256',
digest: 'MUSTVERIFY+ALL/THINGS==',
options: []
},
size: 9001
}
cacache.get.hasContent(cachePath, 'sha521-NOT+IN/CACHE==').then(console.log)
// Output
false
```
#### <a name="put-data"></a> `> cacache.put(cache, key, data, [opts]) -> Promise`
Inserts data passed to it into the cache. The returned Promise resolves with a
digest (generated according to [`opts.algorithms`](#optsalgorithms)) after the
cache entry has been successfully written.
##### Example
```javascript
fetch(
'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
).then(data => {
return cacache.put(cachePath, 'registry.npmjs.org|cacache@1.0.0', data)
}).then(integrity => {
console.log('integrity hash is', integrity)
})
```
#### <a name="put-stream"></a> `> cacache.put.stream(cache, key, [opts]) -> Writable`
Returns a [Writable
Stream](https://nodejs.org/api/stream.html#stream_writable_streams) that inserts
data written to it into the cache. Emits an `integrity` event with the digest of
written contents when it succeeds.
##### Example
```javascript
request.get(
'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
).pipe(
cacache.put.stream(
cachePath, 'registry.npmjs.org|cacache@1.0.0'
).on('integrity', d => console.log(`integrity digest is ${d}`))
)
```
#### <a name="put-options"></a> `> cacache.put options`
`cacache.put` functions have a number of options in common.
##### `opts.metadata`
Arbitrary metadata to be attached to the inserted key.
##### `opts.size`
If provided, the data stream will be verified to check that enough data was
passed through. If there's more or less data than expected, insertion will fail
with an `EBADSIZE` error.
##### `opts.integrity`
If present, the pre-calculated digest for the inserted content. If this option
if provided and does not match the post-insertion digest, insertion will fail
with an `EINTEGRITY` error.
`algorithms` has no effect if this option is present.
##### `opts.algorithms`
Default: ['sha512']
Hashing algorithms to use when calculating the [subresource integrity
digest](#integrity)
for inserted data. Can use any algorithm listed in `crypto.getHashes()` or
`'omakase'`/`'お任せします'` to pick a random hash algorithm on each insertion. You
may also use any anagram of `'modnar'` to use this feature.
Currently only supports one algorithm at a time (i.e., an array length of
exactly `1`). Has no effect if `opts.integrity` is present.
##### `opts.uid`/`opts.gid`
If provided, cacache will do its best to make sure any new files added to the
cache use this particular `uid`/`gid` combination. This can be used,
for example, to drop permissions when someone uses `sudo`, but cacache makes
no assumptions about your needs here.
##### `opts.memoize`
Default: null
If provided, cacache will memoize the given cache insertion in memory, bypassing
any filesystem checks for that key or digest in future cache fetches. Nothing
will be written to the in-memory cache unless this option is explicitly truthy.
If `opts.memoize` is an object or a `Map`-like (that is, an object with `get`
and `set` methods), it will be written to instead of the global memoization
cache.
Reading from disk data can be forced by explicitly passing `memoize: false` to
the reader functions, but their default will be to read from memory.
#### <a name="rm-all"></a> `> cacache.rm.all(cache) -> Promise`
Clears the entire cache. Mainly by blowing away the cache directory itself.
##### Example
```javascript
cacache.rm.all(cachePath).then(() => {
console.log('THE APOCALYPSE IS UPON US 😱')
})
```
#### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key) -> Promise`
Alias: `cacache.rm`
Removes the index entry for `key`. Content will still be accessible if
requested directly by content address ([`get.stream.byDigest`](#get-stream)).
To remove the content itself (which might still be used by other entries), use
[`rm.content`](#rm-content). Or, to safely vacuum any unused content, use
[`verify`](#verify).
##### Example
```javascript
cacache.rm.entry(cachePath, 'my-thing').then(() => {
console.log('I did not like it anyway')
})
```
#### <a name="rm-content"></a> `> cacache.rm.content(cache, integrity) -> Promise`
Removes the content identified by `integrity`. Any index entries referring to it
will not be usable again until the content is re-added to the cache with an
identical digest.
##### Example
```javascript
cacache.rm.content(cachePath, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => {
console.log('data for my-thing is gone!')
})
```
#### <a name="set-locale"></a> `> cacache.setLocale(locale)`
Configure the language/locale used for messages and errors coming from cacache.
The list of available locales is in the `./locales` directory in the project
root.
_Interested in contributing more languages! [Submit a PR](CONTRIBUTING.md)!_
#### <a name="clear-memoized"></a> `> cacache.clearMemoized()`
Completely resets the in-memory entry cache.
#### <a name="tmp-mkdir"></a> `> tmp.mkdir(cache, opts) -> Promise<Path>`
Returns a unique temporary directory inside the cache's `tmp` dir. This
directory will use the same safe user assignment that all the other stuff use.
Once the directory is made, it's the user's responsibility that all files within
are made according to the same `opts.gid`/`opts.uid` settings that would be
passed in. If not, you can ask cacache to do it for you by calling
[`tmp.fix()`](#tmp-fix), which will fix all tmp directory permissions.
If you want automatic cleanup of this directory, use
[`tmp.withTmp()`](#with-tpm)
##### Example
```javascript
cacache.tmp.mkdir(cache).then(dir => {
fs.writeFile(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
})
```
#### <a name="with-tmp"></a> `> tmp.withTmp(cache, opts, cb) -> Promise`
Creates a temporary directory with [`tmp.mkdir()`](#tmp-mkdir) and calls `cb`
with it. The created temporary directory will be removed when the return value
of `cb()` resolves -- that is, if you return a Promise from `cb()`, the tmp
directory will be automatically deleted once that promise completes.
The same caveats apply when it comes to managing permissions for the tmp dir's
contents.
##### Example
```javascript
cacache.tmp.withTmp(cache, dir => {
return fs.writeFileAsync(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
}).then(() => {
// `dir` no longer exists
})
```
#### <a name="integrity"></a> Subresource Integrity Digests
For content verification and addressing, cacache uses strings following the
[Subresource
Integrity spec](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
That is, any time cacache expects an `integrity` argument or option, it
should be in the format `<hashAlgorithm>-<base64-hash>`.
One deviation from the current spec is that cacache will support any hash
algorithms supported by the underlying Node.js process. You can use
`crypto.getHashes()` to see which ones you can use.
##### Generating Digests Yourself
If you have an existing content shasum, they are generally formatted as a
hexadecimal string (that is, a sha1 would look like:
`5f5513f8822fdbe5145af33b64d8d970dcf95c6e`). In order to be compatible with
cacache, you'll need to convert this to an equivalent subresource integrity
string. For this example, the corresponding hash would be:
`sha1-X1UT+IIv2+UUWvM7ZNjZcNz5XG4=`.
If you want to generate an integrity string yourself for existing data, you can
use something like this:
```javascript
const crypto = require('crypto')
const hashAlgorithm = 'sha512'
const data = 'foobarbaz'
const integrity = (
hashAlgorithm +
'-' +
crypto.createHash(hashAlgorithm).update(data).digest('base64')
)
```
You can also use [`ssri`](https://npm.im/ssri) to have a richer set of functionality
around SRI strings, including generation, parsing, and translating from existing
hex-formatted strings.
#### <a name="verify"></a> `> cacache.verify(cache, opts) -> Promise`
Checks out and fixes up your cache:
* Cleans up corrupted or invalid index entries.
* Custom entry filtering options.
* Garbage collects any content entries not referenced by the index.
* Checks integrity for all content entries and removes invalid content.
* Fixes cache ownership.
* Removes the `tmp` directory in the cache and all its contents.
When it's done, it'll return an object with various stats about the verification
process, including amount of storage reclaimed, number of valid entries, number
of entries removed, etc.
##### Options
* `opts.uid` - uid to assign to cache and its contents
* `opts.gid` - gid to assign to cache and its contents
* `opts.filter` - receives a formatted entry. Return false to remove it.
Note: might be called more than once on the same entry.
##### Example
```sh
echo somegarbage >> $CACHEPATH/content/deadbeef
```
```javascript
cacache.verify(cachePath).then(stats => {
// deadbeef collected, because of invalid checksum.
console.log('cache is much nicer now! stats:', stats)
})
```
#### <a name="verify-last-run"></a> `> cacache.verify.lastRun(cache) -> Promise`
Returns a `Date` representing the last time `cacache.verify` was run on `cache`.
##### Example
```javascript
cacache.verify(cachePath).then(() => {
cacache.verify.lastRun(cachePath).then(lastTime => {
console.log('cacache.verify was last called on' + lastTime)
})
})
```
+3
View File
@@ -0,0 +1,3 @@
'use strict'
module.exports = require('./locales/en.js')
+3
View File
@@ -0,0 +1,3 @@
'use strict'
module.exports = require('./locales/es.js')
+190
View File
@@ -0,0 +1,190 @@
'use strict'
const BB = require('bluebird')
const fs = require('fs')
const index = require('./lib/entry-index')
const memo = require('./lib/memoization')
const pipe = require('mississippi').pipe
const pipeline = require('mississippi').pipeline
const read = require('./lib/content/read')
const through = require('mississippi').through
module.exports = function get (cache, key, opts) {
return getData(false, cache, key, opts)
}
module.exports.byDigest = function getByDigest (cache, digest, opts) {
return getData(true, cache, digest, opts)
}
function getData (byDigest, cache, key, opts) {
opts = opts || {}
const memoized = (
byDigest
? memo.get.byDigest(cache, key, opts)
: memo.get(cache, key, opts)
)
if (memoized && opts.memoize !== false) {
return BB.resolve(byDigest ? memoized : {
metadata: memoized.entry.metadata,
data: memoized.data,
integrity: memoized.entry.integrity,
size: memoized.entry.size
})
}
return (
byDigest ? BB.resolve(null) : index.find(cache, key, opts)
).then(entry => {
if (!entry && !byDigest) {
throw new index.NotFoundError(cache, key)
}
return read(cache, byDigest ? key : entry.integrity, {
integrity: opts.integrity,
size: opts.size
}).then(data => byDigest ? data : {
metadata: entry.metadata,
data: data,
size: entry.size,
integrity: entry.integrity
}).then(res => {
if (opts.memoize && byDigest) {
memo.put.byDigest(cache, key, res, opts)
} else if (opts.memoize) {
memo.put(cache, entry, res.data, opts)
}
return res
})
})
}
module.exports.stream = getStream
function getStream (cache, key, opts) {
opts = opts || {}
let stream = through()
const memoized = memo.get(cache, key, opts)
if (memoized && opts.memoize !== false) {
stream.on('newListener', function (ev, cb) {
ev === 'metadata' && cb(memoized.entry.metadata)
ev === 'integrity' && cb(memoized.entry.integrity)
ev === 'size' && cb(memoized.entry.size)
})
stream.write(memoized.data, () => stream.end())
return stream
}
index.find(cache, key).then(entry => {
if (!entry) {
return stream.emit(
'error', new index.NotFoundError(cache, key)
)
}
let memoStream
if (opts.memoize) {
let memoData = []
let memoLength = 0
memoStream = through((c, en, cb) => {
memoData && memoData.push(c)
memoLength += c.length
cb(null, c, en)
}, cb => {
memoData && memo.put(cache, entry, Buffer.concat(memoData, memoLength), opts)
cb()
})
} else {
memoStream = through()
}
opts.size = opts.size == null ? entry.size : opts.size
stream.emit('metadata', entry.metadata)
stream.emit('integrity', entry.integrity)
stream.emit('size', entry.size)
stream.on('newListener', function (ev, cb) {
ev === 'metadata' && cb(entry.metadata)
ev === 'integrity' && cb(entry.integrity)
ev === 'size' && cb(entry.size)
})
pipe(
read.readStream(cache, entry.integrity, opts),
memoStream,
stream
)
}, err => stream.emit('error', err))
return stream
}
module.exports.stream.byDigest = getStreamDigest
function getStreamDigest (cache, integrity, opts) {
opts = opts || {}
const memoized = memo.get.byDigest(cache, integrity, opts)
if (memoized && opts.memoize !== false) {
const stream = through()
stream.write(memoized, () => stream.end())
return stream
} else {
let stream = read.readStream(cache, integrity, opts)
if (opts.memoize) {
let memoData = []
let memoLength = 0
const memoStream = through((c, en, cb) => {
memoData && memoData.push(c)
memoLength += c.length
cb(null, c, en)
}, cb => {
memoData && memo.put.byDigest(
cache,
integrity,
Buffer.concat(memoData, memoLength),
opts
)
cb()
})
stream = pipeline(stream, memoStream)
}
return stream
}
}
module.exports.info = info
function info (cache, key, opts) {
opts = opts || {}
const memoized = memo.get(cache, key, opts)
if (memoized && opts.memoize !== false) {
return BB.resolve(memoized.entry)
} else {
return index.find(cache, key)
}
}
module.exports.hasContent = read.hasContent
module.exports.copy = function cp (cache, key, dest, opts) {
return copy(false, cache, key, dest, opts)
}
module.exports.copy.byDigest = function cpDigest (cache, digest, dest, opts) {
return copy(true, cache, digest, dest, opts)
}
function copy (byDigest, cache, key, dest, opts) {
opts = opts || {}
if (read.copy) {
return (
byDigest ? BB.resolve(null) : index.find(cache, key, opts)
).then(entry => {
if (!entry && !byDigest) {
throw new index.NotFoundError(cache, key)
}
return read.copy(
cache, byDigest ? key : entry.integrity, dest, opts
).then(() => byDigest ? key : {
metadata: entry.metadata,
size: entry.size,
integrity: entry.integrity
})
})
} else {
return getData(byDigest, cache, key, opts).then(res => {
return fs.writeFileAsync(dest, byDigest ? res : res.data)
.then(() => byDigest ? key : {
metadata: res.metadata,
size: res.size,
integrity: res.integrity
})
})
}
}
+3
View File
@@ -0,0 +1,3 @@
'use strict'
module.exports = require('./locales/en.js')
@@ -0,0 +1,26 @@
'use strict'
const contentVer = require('../../package.json')['cache-version'].content
const hashToSegments = require('../util/hash-to-segments')
const path = require('path')
const ssri = require('ssri')
// Current format of content file path:
//
// sha512-BaSE64Hex= ->
// ~/.my-cache/content-v2/sha512/ba/da/55deadbeefc0ffee
//
module.exports = contentPath
function contentPath (cache, integrity) {
const sri = ssri.parse(integrity, {single: true})
// contentPath is the *strongest* algo given
return path.join.apply(path, [
contentDir(cache),
sri.algorithm
].concat(hashToSegments(sri.hexDigest())))
}
module.exports._contentDir = contentDir
function contentDir (cache) {
return path.join(cache, `content-v${contentVer}`)
}
@@ -0,0 +1,125 @@
'use strict'
const BB = require('bluebird')
const contentPath = require('./path')
const fs = require('graceful-fs')
const PassThrough = require('stream').PassThrough
const pipe = BB.promisify(require('mississippi').pipe)
const ssri = require('ssri')
const Y = require('../util/y.js')
BB.promisifyAll(fs)
module.exports = read
function read (cache, integrity, opts) {
opts = opts || {}
return pickContentSri(cache, integrity).then(content => {
const sri = content.sri
const cpath = contentPath(cache, sri)
return fs.readFileAsync(cpath, null).then(data => {
if (typeof opts.size === 'number' && opts.size !== data.length) {
throw sizeError(opts.size, data.length)
} else if (ssri.checkData(data, sri)) {
return data
} else {
throw integrityError(sri, cpath)
}
})
})
}
module.exports.stream = readStream
module.exports.readStream = readStream
function readStream (cache, integrity, opts) {
opts = opts || {}
const stream = new PassThrough()
pickContentSri(
cache, integrity
).then(content => {
const sri = content.sri
return pipe(
fs.createReadStream(contentPath(cache, sri)),
ssri.integrityStream({
integrity: sri,
size: opts.size
}),
stream
)
}).catch(err => {
stream.emit('error', err)
})
return stream
}
if (fs.copyFile) {
module.exports.copy = copy
}
function copy (cache, integrity, dest, opts) {
opts = opts || {}
return pickContentSri(cache, integrity).then(content => {
const sri = content.sri
const cpath = contentPath(cache, sri)
return fs.copyFileAsync(cpath, dest).then(() => content.size)
})
}
module.exports.hasContent = hasContent
function hasContent (cache, integrity) {
if (!integrity) { return BB.resolve(false) }
return pickContentSri(cache, integrity)
.catch({code: 'ENOENT'}, () => false)
.catch({code: 'EPERM'}, err => {
if (process.platform !== 'win32') {
throw err
} else {
return false
}
}).then(content => {
if (!content.sri) return false
return ({ sri: content.sri, size: content.stat.size })
})
}
module.exports._pickContentSri = pickContentSri
function pickContentSri (cache, integrity) {
const sri = ssri.parse(integrity)
// If `integrity` has multiple entries, pick the first digest
// with available local data.
const algo = sri.pickAlgorithm()
const digests = sri[algo]
if (digests.length <= 1) {
const cpath = contentPath(cache, digests[0])
return fs.lstatAsync(cpath).then(stat => ({ sri: digests[0], stat }))
} else {
return BB.any(sri[sri.pickAlgorithm()].map(meta => {
return pickContentSri(cache, meta)
}))
.catch(err => {
if ([].some.call(err, e => e.code === 'ENOENT')) {
throw Object.assign(
new Error('No matching content found for ' + sri.toString()),
{code: 'ENOENT'}
)
} else {
throw err[0]
}
})
}
}
function sizeError (expected, found) {
var err = new Error(Y`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
err.expected = expected
err.found = found
err.code = 'EBADSIZE'
return err
}
function integrityError (sri, path) {
var err = new Error(Y`Integrity verification failed for ${sri} (${path})`)
err.code = 'EINTEGRITY'
err.sri = sri
err.path = path
return err
}
@@ -0,0 +1,21 @@
'use strict'
const BB = require('bluebird')
const contentPath = require('./path')
const hasContent = require('./read').hasContent
const rimraf = BB.promisify(require('rimraf'))
module.exports = rm
function rm (cache, integrity) {
return hasContent(cache, integrity).then(content => {
if (content) {
const sri = content.sri
if (sri) {
return rimraf(contentPath(cache, sri)).then(() => true)
}
} else {
return false
}
})
}
@@ -0,0 +1,162 @@
'use strict'
const BB = require('bluebird')
const contentPath = require('./path')
const fixOwner = require('../util/fix-owner')
const fs = require('graceful-fs')
const moveFile = require('../util/move-file')
const PassThrough = require('stream').PassThrough
const path = require('path')
const pipe = BB.promisify(require('mississippi').pipe)
const rimraf = BB.promisify(require('rimraf'))
const ssri = require('ssri')
const to = require('mississippi').to
const uniqueFilename = require('unique-filename')
const Y = require('../util/y.js')
const writeFileAsync = BB.promisify(fs.writeFile)
module.exports = write
function write (cache, data, opts) {
opts = opts || {}
if (opts.algorithms && opts.algorithms.length > 1) {
throw new Error(
Y`opts.algorithms only supports a single algorithm for now`
)
}
if (typeof opts.size === 'number' && data.length !== opts.size) {
return BB.reject(sizeError(opts.size, data.length))
}
const sri = ssri.fromData(data, opts)
if (opts.integrity && !ssri.checkData(data, opts.integrity, opts)) {
return BB.reject(checksumError(opts.integrity, sri))
}
return BB.using(makeTmp(cache, opts), tmp => (
writeFileAsync(
tmp.target, data, {flag: 'wx'}
).then(() => (
moveToDestination(tmp, cache, sri, opts)
))
)).then(() => ({integrity: sri, size: data.length}))
}
module.exports.stream = writeStream
function writeStream (cache, opts) {
opts = opts || {}
const inputStream = new PassThrough()
let inputErr = false
function errCheck () {
if (inputErr) { throw inputErr }
}
let allDone
const ret = to((c, n, cb) => {
if (!allDone) {
allDone = handleContent(inputStream, cache, opts, errCheck)
}
inputStream.write(c, n, cb)
}, cb => {
inputStream.end(() => {
if (!allDone) {
const e = new Error(Y`Cache input stream was empty`)
e.code = 'ENODATA'
return ret.emit('error', e)
}
allDone.then(res => {
res.integrity && ret.emit('integrity', res.integrity)
res.size !== null && ret.emit('size', res.size)
cb()
}, e => {
ret.emit('error', e)
})
})
})
ret.once('error', e => {
inputErr = e
})
return ret
}
function handleContent (inputStream, cache, opts, errCheck) {
return BB.using(makeTmp(cache, opts), tmp => {
errCheck()
return pipeToTmp(
inputStream, cache, tmp.target, opts, errCheck
).then(res => {
return moveToDestination(
tmp, cache, res.integrity, opts, errCheck
).then(() => res)
})
})
}
function pipeToTmp (inputStream, cache, tmpTarget, opts, errCheck) {
return BB.resolve().then(() => {
let integrity
let size
const hashStream = ssri.integrityStream({
integrity: opts.integrity,
algorithms: opts.algorithms,
size: opts.size
}).on('integrity', s => {
integrity = s
}).on('size', s => {
size = s
})
const outStream = fs.createWriteStream(tmpTarget, {
flags: 'wx'
})
errCheck()
return pipe(inputStream, hashStream, outStream).then(() => {
return {integrity, size}
}, err => {
return rimraf(tmpTarget).then(() => { throw err })
})
})
}
function makeTmp (cache, opts) {
const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
return fixOwner.mkdirfix(
path.dirname(tmpTarget), opts.uid, opts.gid
).then(() => ({
target: tmpTarget,
moved: false
})).disposer(tmp => (!tmp.moved && rimraf(tmp.target)))
}
function moveToDestination (tmp, cache, sri, opts, errCheck) {
errCheck && errCheck()
const destination = contentPath(cache, sri)
const destDir = path.dirname(destination)
return fixOwner.mkdirfix(
destDir, opts.uid, opts.gid
).then(() => {
errCheck && errCheck()
return moveFile(tmp.target, destination)
}).then(() => {
errCheck && errCheck()
tmp.moved = true
return fixOwner.chownr(destination, opts.uid, opts.gid)
})
}
function sizeError (expected, found) {
var err = new Error(Y`Bad data size: expected inserted data to be ${expected} bytes, but got ${found} instead`)
err.expected = expected
err.found = found
err.code = 'EBADSIZE'
return err
}
function checksumError (expected, found) {
var err = new Error(Y`Integrity check failed:
Wanted: ${expected}
Found: ${found}`)
err.code = 'EINTEGRITY'
err.expected = expected
err.found = found
return err
}
@@ -0,0 +1,225 @@
'use strict'
const BB = require('bluebird')
const contentPath = require('./content/path')
const crypto = require('crypto')
const fixOwner = require('./util/fix-owner')
const fs = require('graceful-fs')
const hashToSegments = require('./util/hash-to-segments')
const ms = require('mississippi')
const path = require('path')
const ssri = require('ssri')
const Y = require('./util/y.js')
const indexV = require('../package.json')['cache-version'].index
const appendFileAsync = BB.promisify(fs.appendFile)
const readFileAsync = BB.promisify(fs.readFile)
const readdirAsync = BB.promisify(fs.readdir)
const concat = ms.concat
const from = ms.from
module.exports.NotFoundError = class NotFoundError extends Error {
constructor (cache, key) {
super(Y`No cache entry for \`${key}\` found in \`${cache}\``)
this.code = 'ENOENT'
this.cache = cache
this.key = key
}
}
module.exports.insert = insert
function insert (cache, key, integrity, opts) {
opts = opts || {}
const bucket = bucketPath(cache, key)
const entry = {
key,
integrity: integrity && ssri.stringify(integrity),
time: Date.now(),
size: opts.size,
metadata: opts.metadata
}
return fixOwner.mkdirfix(
path.dirname(bucket), opts.uid, opts.gid
).then(() => {
const stringified = JSON.stringify(entry)
// NOTE - Cleverness ahoy!
//
// This works because it's tremendously unlikely for an entry to corrupt
// another while still preserving the string length of the JSON in
// question. So, we just slap the length in there and verify it on read.
//
// Thanks to @isaacs for the whiteboarding session that ended up with this.
return appendFileAsync(
bucket, `\n${hashEntry(stringified)}\t${stringified}`
)
}).then(
() => fixOwner.chownr(bucket, opts.uid, opts.gid)
).catch({code: 'ENOENT'}, () => {
// There's a class of race conditions that happen when things get deleted
// during fixOwner, or between the two mkdirfix/chownr calls.
//
// It's perfectly fine to just not bother in those cases and lie
// that the index entry was written. Because it's a cache.
}).then(() => {
return formatEntry(cache, entry)
})
}
module.exports.find = find
function find (cache, key) {
const bucket = bucketPath(cache, key)
return bucketEntries(cache, bucket).then(entries => {
return entries.reduce((latest, next) => {
if (next && next.key === key) {
return formatEntry(cache, next)
} else {
return latest
}
}, null)
}).catch(err => {
if (err.code === 'ENOENT') {
return null
} else {
throw err
}
})
}
module.exports.delete = del
function del (cache, key, opts) {
return insert(cache, key, null, opts)
}
module.exports.lsStream = lsStream
function lsStream (cache) {
const indexDir = bucketDir(cache)
const stream = from.obj()
// "/cachename/*"
readdirOrEmpty(indexDir).map(bucket => {
const bucketPath = path.join(indexDir, bucket)
// "/cachename/<bucket 0xFF>/*"
return readdirOrEmpty(bucketPath).map(subbucket => {
const subbucketPath = path.join(bucketPath, subbucket)
// "/cachename/<bucket 0xFF>/<bucket 0xFF>/*"
return readdirOrEmpty(subbucketPath).map(entry => {
const getKeyToEntry = bucketEntries(
cache,
path.join(subbucketPath, entry)
).reduce((acc, entry) => {
acc.set(entry.key, entry)
return acc
}, new Map())
return getKeyToEntry.then(reduced => {
for (let entry of reduced.values()) {
const formatted = formatEntry(cache, entry)
formatted && stream.push(formatted)
}
}).catch({code: 'ENOENT'}, nop)
})
})
}).then(() => {
stream.push(null)
}, err => {
stream.emit('error', err)
})
return stream
}
module.exports.ls = ls
function ls (cache) {
return BB.fromNode(cb => {
lsStream(cache).on('error', cb).pipe(concat(entries => {
cb(null, entries.reduce((acc, xs) => {
acc[xs.key] = xs
return acc
}, {}))
}))
})
}
function bucketEntries (cache, bucket, filter) {
return readFileAsync(
bucket, 'utf8'
).then(data => {
let entries = []
data.split('\n').forEach(entry => {
if (!entry) { return }
const pieces = entry.split('\t')
if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) {
// Hash is no good! Corruption or malice? Doesn't matter!
// EJECT EJECT
return
}
let obj
try {
obj = JSON.parse(pieces[1])
} catch (e) {
// Entry is corrupted!
return
}
if (obj) {
entries.push(obj)
}
})
return entries
})
}
module.exports._bucketDir = bucketDir
function bucketDir (cache) {
return path.join(cache, `index-v${indexV}`)
}
module.exports._bucketPath = bucketPath
function bucketPath (cache, key) {
const hashed = hashKey(key)
return path.join.apply(path, [bucketDir(cache)].concat(
hashToSegments(hashed)
))
}
module.exports._hashKey = hashKey
function hashKey (key) {
return hash(key, 'sha256')
}
module.exports._hashEntry = hashEntry
function hashEntry (str) {
return hash(str, 'sha1')
}
function hash (str, digest) {
return crypto
.createHash(digest)
.update(str)
.digest('hex')
}
function formatEntry (cache, entry) {
// Treat null digests as deletions. They'll shadow any previous entries.
if (!entry.integrity) { return null }
return {
key: entry.key,
integrity: entry.integrity,
path: contentPath(cache, entry.integrity),
size: entry.size,
time: entry.time,
metadata: entry.metadata
}
}
function readdirOrEmpty (dir) {
return readdirAsync(dir)
.catch({code: 'ENOENT'}, () => [])
.catch({code: 'ENOTDIR'}, () => [])
}
function nop () {
}
@@ -0,0 +1,69 @@
'use strict'
const LRU = require('lru-cache')
const MAX_SIZE = 50 * 1024 * 1024 // 50MB
const MAX_AGE = 3 * 60 * 1000
let MEMOIZED = new LRU({
max: MAX_SIZE,
maxAge: MAX_AGE,
length: (entry, key) => {
if (key.startsWith('key:')) {
return entry.data.length
} else if (key.startsWith('digest:')) {
return entry.length
}
}
})
module.exports.clearMemoized = clearMemoized
function clearMemoized () {
const old = {}
MEMOIZED.forEach((v, k) => {
old[k] = v
})
MEMOIZED.reset()
return old
}
module.exports.put = put
function put (cache, entry, data, opts) {
pickMem(opts).set(`key:${cache}:${entry.key}`, { entry, data })
putDigest(cache, entry.integrity, data, opts)
}
module.exports.put.byDigest = putDigest
function putDigest (cache, integrity, data, opts) {
pickMem(opts).set(`digest:${cache}:${integrity}`, data)
}
module.exports.get = get
function get (cache, key, opts) {
return pickMem(opts).get(`key:${cache}:${key}`)
}
module.exports.get.byDigest = getDigest
function getDigest (cache, integrity, opts) {
return pickMem(opts).get(`digest:${cache}:${integrity}`)
}
class ObjProxy {
constructor (obj) {
this.obj = obj
}
get (key) { return this.obj[key] }
set (key, val) { this.obj[key] = val }
}
function pickMem (opts) {
if (!opts || !opts.memoize) {
return MEMOIZED
} else if (opts.memoize.get && opts.memoize.set) {
return opts.memoize
} else if (typeof opts.memoize === 'object') {
return new ObjProxy(opts.memoize)
} else {
return MEMOIZED
}
}
@@ -0,0 +1,44 @@
'use strict'
const BB = require('bluebird')
const chownr = BB.promisify(require('chownr'))
const mkdirp = BB.promisify(require('mkdirp'))
const inflight = require('promise-inflight')
module.exports.chownr = fixOwner
function fixOwner (filepath, uid, gid) {
if (!process.getuid) {
// This platform doesn't need ownership fixing
return BB.resolve()
}
if (typeof uid !== 'number' && typeof gid !== 'number') {
// There's no permissions override. Nothing to do here.
return BB.resolve()
}
if ((typeof uid === 'number' && process.getuid() === uid) &&
(typeof gid === 'number' && process.getgid() === gid)) {
// No need to override if it's already what we used.
return BB.resolve()
}
return inflight(
'fixOwner: fixing ownership on ' + filepath,
() => chownr(
filepath,
typeof uid === 'number' ? uid : process.getuid(),
typeof gid === 'number' ? gid : process.getgid()
).catch({code: 'ENOENT'}, () => null)
)
}
module.exports.mkdirfix = mkdirfix
function mkdirfix (p, uid, gid, cb) {
return mkdirp(p).then(made => {
if (made) {
return fixOwner(made, uid, gid).then(() => made)
}
}).catch({code: 'EEXIST'}, () => {
// There's a race in mkdirp!
return fixOwner(p, uid, gid).then(() => null)
})
}
@@ -0,0 +1,11 @@
'use strict'
module.exports = hashToSegments
function hashToSegments (hash) {
return [
hash.slice(0, 2),
hash.slice(2, 4),
hash.slice(4)
]
}
@@ -0,0 +1,51 @@
'use strict'
const fs = require('graceful-fs')
const BB = require('bluebird')
const chmod = BB.promisify(fs.chmod)
const unlink = BB.promisify(fs.unlink)
let move
let pinflight
module.exports = moveFile
function moveFile (src, dest) {
// This isn't quite an fs.rename -- the assumption is that
// if `dest` already exists, and we get certain errors while
// trying to move it, we should just not bother.
//
// In the case of cache corruption, users will receive an
// EINTEGRITY error elsewhere, and can remove the offending
// content their own way.
//
// Note that, as the name suggests, this strictly only supports file moves.
return BB.fromNode(cb => {
fs.link(src, dest, err => {
if (err) {
if (err.code === 'EEXIST' || err.code === 'EBUSY') {
// file already exists, so whatever
} else if (err.code === 'EPERM' && process.platform === 'win32') {
// file handle stayed open even past graceful-fs limits
} else {
return cb(err)
}
}
return cb()
})
}).then(() => {
// content should never change for any reason, so make it read-only
return BB.join(unlink(src), process.platform !== 'win32' && chmod(dest, '0444'))
}).catch(() => {
if (!pinflight) { pinflight = require('promise-inflight') }
return pinflight('cacache-move-file:' + dest, () => {
return BB.promisify(fs.stat)(dest).catch(err => {
if (err.code !== 'ENOENT') {
// Something else is wrong here. Bail bail bail
throw err
}
// file doesn't already exist! let's try a rename -> copy fallback
if (!move) { move = require('move-concurrently') }
return move(src, dest, { BB, fs })
})
})
})
}
+32
View File
@@ -0,0 +1,32 @@
'use strict'
const BB = require('bluebird')
const fixOwner = require('./fix-owner')
const path = require('path')
const rimraf = BB.promisify(require('rimraf'))
const uniqueFilename = require('unique-filename')
module.exports.mkdir = mktmpdir
function mktmpdir (cache, opts) {
opts = opts || {}
const tmpTarget = uniqueFilename(path.join(cache, 'tmp'), opts.tmpPrefix)
return fixOwner.mkdirfix(tmpTarget, opts.uid, opts.gid).then(() => {
return tmpTarget
})
}
module.exports.withTmp = withTmp
function withTmp (cache, opts, cb) {
if (!cb) {
cb = opts
opts = null
}
opts = opts || {}
return BB.using(mktmpdir(cache, opts).disposer(rimraf), cb)
}
module.exports.fix = fixtmpdir
function fixtmpdir (cache, opts) {
return fixOwner(path.join(cache, 'tmp'), opts.uid, opts.gid)
}
+25
View File
@@ -0,0 +1,25 @@
'use strict'
const path = require('path')
const y18n = require('y18n')({
directory: path.join(__dirname, '../../locales'),
locale: 'en',
updateFiles: process.env.CACACHE_UPDATE_LOCALE_FILES === 'true'
})
module.exports = yTag
function yTag (parts) {
let str = ''
parts.forEach((part, i) => {
const arg = arguments[i + 1]
str += part
if (arg) {
str += '%s'
}
})
return y18n.__.apply(null, [str].concat([].slice.call(arguments, 1)))
}
module.exports.setLocale = locale => {
y18n.setLocale(locale)
}
+213
View File
@@ -0,0 +1,213 @@
'use strict'
const BB = require('bluebird')
const contentPath = require('./content/path')
const finished = BB.promisify(require('mississippi').finished)
const fixOwner = require('./util/fix-owner')
const fs = require('graceful-fs')
const glob = BB.promisify(require('glob'))
const index = require('./entry-index')
const path = require('path')
const rimraf = BB.promisify(require('rimraf'))
const ssri = require('ssri')
BB.promisifyAll(fs)
module.exports = verify
function verify (cache, opts) {
opts = opts || {}
opts.log && opts.log.silly('verify', 'verifying cache at', cache)
return BB.reduce([
markStartTime,
fixPerms,
garbageCollect,
rebuildIndex,
cleanTmp,
writeVerifile,
markEndTime
], (stats, step, i) => {
const label = step.name || `step #${i}`
const start = new Date()
return BB.resolve(step(cache, opts)).then(s => {
s && Object.keys(s).forEach(k => {
stats[k] = s[k]
})
const end = new Date()
if (!stats.runTime) { stats.runTime = {} }
stats.runTime[label] = end - start
return stats
})
}, {}).tap(stats => {
stats.runTime.total = stats.endTime - stats.startTime
opts.log && opts.log.silly('verify', 'verification finished for', cache, 'in', `${stats.runTime.total}ms`)
})
}
function markStartTime (cache, opts) {
return { startTime: new Date() }
}
function markEndTime (cache, opts) {
return { endTime: new Date() }
}
function fixPerms (cache, opts) {
opts.log && opts.log.silly('verify', 'fixing cache permissions')
return fixOwner.mkdirfix(cache, opts.uid, opts.gid).then(() => {
// TODO - fix file permissions too
return fixOwner.chownr(cache, opts.uid, opts.gid)
}).then(() => null)
}
// Implements a naive mark-and-sweep tracing garbage collector.
//
// The algorithm is basically as follows:
// 1. Read (and filter) all index entries ("pointers")
// 2. Mark each integrity value as "live"
// 3. Read entire filesystem tree in `content-vX/` dir
// 4. If content is live, verify its checksum and delete it if it fails
// 5. If content is not marked as live, rimraf it.
//
function garbageCollect (cache, opts) {
opts.log && opts.log.silly('verify', 'garbage collecting content')
const indexStream = index.lsStream(cache)
const liveContent = new Set()
indexStream.on('data', entry => {
if (opts && opts.filter && !opts.filter(entry)) { return }
liveContent.add(entry.integrity.toString())
})
return finished(indexStream).then(() => {
const contentDir = contentPath._contentDir(cache)
return glob(path.join(contentDir, '**'), {
follow: false,
nodir: true,
nosort: true
}).then(files => {
return BB.resolve({
verifiedContent: 0,
reclaimedCount: 0,
reclaimedSize: 0,
badContentCount: 0,
keptSize: 0
}).tap((stats) => BB.map(files, (f) => {
const split = f.split(/[/\\]/)
const digest = split.slice(split.length - 3).join('')
const algo = split[split.length - 4]
const integrity = ssri.fromHex(digest, algo)
if (liveContent.has(integrity.toString())) {
return verifyContent(f, integrity).then(info => {
if (!info.valid) {
stats.reclaimedCount++
stats.badContentCount++
stats.reclaimedSize += info.size
} else {
stats.verifiedContent++
stats.keptSize += info.size
}
return stats
})
} else {
// No entries refer to this content. We can delete.
stats.reclaimedCount++
return fs.statAsync(f).then(s => {
return rimraf(f).then(() => {
stats.reclaimedSize += s.size
return stats
})
})
}
}, {concurrency: opts.concurrency || 20}))
})
})
}
function verifyContent (filepath, sri) {
return fs.statAsync(filepath).then(stat => {
const contentInfo = {
size: stat.size,
valid: true
}
return ssri.checkStream(
fs.createReadStream(filepath),
sri
).catch(err => {
if (err.code !== 'EINTEGRITY') { throw err }
return rimraf(filepath).then(() => {
contentInfo.valid = false
})
}).then(() => contentInfo)
}).catch({code: 'ENOENT'}, () => ({size: 0, valid: false}))
}
function rebuildIndex (cache, opts) {
opts.log && opts.log.silly('verify', 'rebuilding index')
return index.ls(cache).then(entries => {
const stats = {
missingContent: 0,
rejectedEntries: 0,
totalEntries: 0
}
const buckets = {}
for (let k in entries) {
if (entries.hasOwnProperty(k)) {
const hashed = index._hashKey(k)
const entry = entries[k]
const excluded = opts && opts.filter && !opts.filter(entry)
excluded && stats.rejectedEntries++
if (buckets[hashed] && !excluded) {
buckets[hashed].push(entry)
} else if (buckets[hashed] && excluded) {
// skip
} else if (excluded) {
buckets[hashed] = []
buckets[hashed]._path = index._bucketPath(cache, k)
} else {
buckets[hashed] = [entry]
buckets[hashed]._path = index._bucketPath(cache, k)
}
}
}
return BB.map(Object.keys(buckets), key => {
return rebuildBucket(cache, buckets[key], stats, opts)
}, {concurrency: opts.concurrency || 20}).then(() => stats)
})
}
function rebuildBucket (cache, bucket, stats, opts) {
return fs.truncateAsync(bucket._path).then(() => {
// This needs to be serialized because cacache explicitly
// lets very racy bucket conflicts clobber each other.
return BB.mapSeries(bucket, entry => {
const content = contentPath(cache, entry.integrity)
return fs.statAsync(content).then(() => {
return index.insert(cache, entry.key, entry.integrity, {
uid: opts.uid,
gid: opts.gid,
metadata: entry.metadata
}).then(() => { stats.totalEntries++ })
}).catch({code: 'ENOENT'}, () => {
stats.rejectedEntries++
stats.missingContent++
})
})
})
}
function cleanTmp (cache, opts) {
opts.log && opts.log.silly('verify', 'cleaning tmp directory')
return rimraf(path.join(cache, 'tmp'))
}
function writeVerifile (cache, opts) {
const verifile = path.join(cache, '_lastverified')
opts.log && opts.log.silly('verify', 'writing verifile to ' + verifile)
return fs.writeFileAsync(verifile, '' + (+(new Date())))
}
module.exports.lastRun = lastRun
function lastRun (cache) {
return fs.readFileAsync(
path.join(cache, '_lastverified'), 'utf8'
).then(data => new Date(+data))
}
+44
View File
@@ -0,0 +1,44 @@
'use strict'
const ls = require('../ls.js')
const get = require('../get.js')
const put = require('../put.js')
const rm = require('../rm.js')
const verify = require('../verify.js')
const setLocale = require('../lib/util/y.js').setLocale
const clearMemoized = require('../lib/memoization.js').clearMemoized
const tmp = require('../lib/util/tmp.js')
setLocale('en')
const x = module.exports
x.ls = cache => ls(cache)
x.ls.stream = cache => ls.stream(cache)
x.get = (cache, key, opts) => get(cache, key, opts)
x.get.byDigest = (cache, hash, opts) => get.byDigest(cache, hash, opts)
x.get.stream = (cache, key, opts) => get.stream(cache, key, opts)
x.get.stream.byDigest = (cache, hash, opts) => get.stream.byDigest(cache, hash, opts)
x.get.copy = (cache, key, dest, opts) => get.copy(cache, key, dest, opts)
x.get.copy.byDigest = (cache, hash, dest, opts) => get.copy.byDigest(cache, hash, dest, opts)
x.get.info = (cache, key) => get.info(cache, key)
x.get.hasContent = (cache, hash) => get.hasContent(cache, hash)
x.put = (cache, key, data, opts) => put(cache, key, data, opts)
x.put.stream = (cache, key, opts) => put.stream(cache, key, opts)
x.rm = (cache, key) => rm.entry(cache, key)
x.rm.all = cache => rm.all(cache)
x.rm.entry = x.rm
x.rm.content = (cache, hash) => rm.content(cache, hash)
x.setLocale = lang => setLocale(lang)
x.clearMemoized = () => clearMemoized()
x.tmp = {}
x.tmp.mkdir = (cache, opts) => tmp.mkdir(cache, opts)
x.tmp.withTmp = (cache, opts, cb) => tmp.withTmp(cache, opts, cb)
x.verify = (cache, opts) => verify(cache, opts)
x.verify.lastRun = cache => verify.lastRun(cache)
@@ -0,0 +1,6 @@
{
"No cache entry for `%s` found in `%s`": "No cache entry for %s found in %s",
"Integrity verification failed for %s (%s)": "Integrity verification failed for %s (%s)",
"Bad data size: expected inserted data to be %s bytes, but got %s instead": "Bad data size: expected inserted data to be %s bytes, but got %s instead",
"Cache input stream was empty": "Cache input stream was empty"
}
+46
View File
@@ -0,0 +1,46 @@
'use strict'
const ls = require('../ls.js')
const get = require('../get.js')
const put = require('../put.js')
const rm = require('../rm.js')
const verify = require('../verify.js')
const setLocale = require('../lib/util/y.js').setLocale
const clearMemoized = require('../lib/memoization.js').clearMemoized
const tmp = require('../lib/util/tmp.js')
setLocale('es')
const x = module.exports
x.ls = cache => ls(cache)
x.ls.flujo = cache => ls.stream(cache)
x.saca = (cache, clave, ops) => get(cache, clave, ops)
x.saca.porHacheo = (cache, hacheo, ops) => get.byDigest(cache, hacheo, ops)
x.saca.flujo = (cache, clave, ops) => get.stream(cache, clave, ops)
x.saca.flujo.porHacheo = (cache, hacheo, ops) => get.stream.byDigest(cache, hacheo, ops)
x.sava.copia = (cache, clave, destino, opts) => get.copy(cache, clave, destino, opts)
x.sava.copia.porHacheo = (cache, hacheo, destino, opts) => get.copy.byDigest(cache, hacheo, destino, opts)
x.saca.info = (cache, clave) => get.info(cache, clave)
x.saca.tieneDatos = (cache, hacheo) => get.hasContent(cache, hacheo)
x.mete = (cache, clave, datos, ops) => put(cache, clave, datos, ops)
x.mete.flujo = (cache, clave, ops) => put.stream(cache, clave, ops)
x.rm = (cache, clave) => rm.entry(cache, clave)
x.rm.todo = cache => rm.all(cache)
x.rm.entrada = x.rm
x.rm.datos = (cache, hacheo) => rm.content(cache, hacheo)
x.ponLenguaje = lang => setLocale(lang)
x.limpiaMemoizado = () => clearMemoized()
x.tmp = {}
x.tmp.mkdir = (cache, ops) => tmp.mkdir(cache, ops)
x.tmp.hazdir = x.tmp.mkdir
x.tmp.conTmp = (cache, ops, cb) => tmp.withTmp(cache, ops, cb)
x.verifica = (cache, ops) => verify(cache, ops)
x.verifica.ultimaVez = cache => verify.lastRun(cache)
x.verifica.últimaVez = x.verifica.ultimaVez
@@ -0,0 +1,6 @@
{
"No cache entry for `%s` found in `%s`": "No existe ninguna entrada para «%s» en «%s»",
"Integrity verification failed for %s (%s)": "Verificación de integridad falló para «%s» (%s)",
"Bad data size: expected inserted data to be %s bytes, but got %s instead": "Tamaño incorrecto de datos: los datos insertados debieron haber sido %s octetos, pero fueron %s",
"Cache input stream was empty": "El stream de entrada al caché estaba vacío"
}
+6
View File
@@ -0,0 +1,6 @@
'use strict'
var index = require('./lib/entry-index')
module.exports = index.ls
module.exports.stream = index.lsStream
+126
View File
@@ -0,0 +1,126 @@
{
"_from": "cacache@^10.0.4",
"_id": "cacache@10.0.4",
"_inBundle": false,
"_integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==",
"_location": "/copy-webpack-plugin/cacache",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "cacache@^10.0.4",
"name": "cacache",
"escapedName": "cacache",
"rawSpec": "^10.0.4",
"saveSpec": null,
"fetchSpec": "^10.0.4"
},
"_requiredBy": [
"/copy-webpack-plugin"
],
"_resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz",
"_shasum": "6452367999eff9d4188aefd9a14e9d7c6a263460",
"_spec": "cacache@^10.0.4",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin",
"author": {
"name": "Kat Marchán",
"email": "kzm@sykosomatic.org"
},
"bugs": {
"url": "https://github.com/zkat/cacache/issues"
},
"bundleDependencies": false,
"cache-version": {
"content": "2",
"index": "5"
},
"config": {
"nyc": {
"exclude": [
"node_modules/**",
"test/**"
]
}
},
"contributors": [
{
"name": "Charlotte Spencer",
"email": "charlottelaspencer@gmail.com"
},
{
"name": "Rebecca Turner",
"email": "me@re-becca.org"
}
],
"dependencies": {
"bluebird": "^3.5.1",
"chownr": "^1.0.1",
"glob": "^7.1.2",
"graceful-fs": "^4.1.11",
"lru-cache": "^4.1.1",
"mississippi": "^2.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.2",
"ssri": "^5.2.4",
"unique-filename": "^1.1.0",
"y18n": "^4.0.0"
},
"deprecated": false,
"description": "Fast, fault-tolerant, cross-platform, disk-based, data-agnostic, content-addressable cache.",
"devDependencies": {
"benchmark": "^2.1.4",
"chalk": "^2.3.1",
"cross-env": "^5.1.3",
"nyc": "^11.4.1",
"require-inject": "^1.4.2",
"safe-buffer": "^5.1.1",
"standard": "^10.0.3",
"standard-version": "^4.3.0",
"tacks": "^1.2.2",
"tap": "^11.1.0",
"weallbehave": "^1.2.0",
"weallcontribute": "^1.0.8"
},
"files": [
"*.js",
"lib",
"locales"
],
"homepage": "https://github.com/zkat/cacache#readme",
"keywords": [
"cache",
"caching",
"content-addressable",
"sri",
"sri hash",
"subresource integrity",
"cache",
"storage",
"store",
"file store",
"filesystem",
"disk cache",
"disk storage"
],
"license": "ISC",
"main": "index.js",
"name": "cacache",
"repository": {
"type": "git",
"url": "git+https://github.com/zkat/cacache.git"
},
"scripts": {
"benchmarks": "node test/benchmarks",
"postrelease": "npm publish && git push --follow-tags",
"prerelease": "npm t",
"pretest": "standard",
"release": "standard-version -s",
"test": "cross-env CACACHE_UPDATE_LOCALE_FILES=true nyc --all -- tap -J test/*.js",
"test-docker": "docker run -it --rm --name pacotest -v \"$PWD\":/tmp -w /tmp node:latest npm test",
"update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'",
"update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'"
},
"version": "10.0.4"
}
+71
View File
@@ -0,0 +1,71 @@
'use strict'
const index = require('./lib/entry-index')
const memo = require('./lib/memoization')
const write = require('./lib/content/write')
const to = require('mississippi').to
module.exports = putData
function putData (cache, key, data, opts) {
opts = opts || {}
return write(cache, data, opts).then(res => {
// TODO - stop modifying opts
opts.size = res.size
return index.insert(cache, key, res.integrity, opts).then(entry => {
if (opts.memoize) {
memo.put(cache, entry, data, opts)
}
return res.integrity
})
})
}
module.exports.stream = putStream
function putStream (cache, key, opts) {
opts = opts || {}
let integrity
let size
const contentStream = write.stream(
cache, opts
).on('integrity', int => {
integrity = int
}).on('size', s => {
size = s
})
let memoData
let memoTotal = 0
const stream = to((chunk, enc, cb) => {
contentStream.write(chunk, enc, () => {
if (opts.memoize) {
if (!memoData) { memoData = [] }
memoData.push(chunk)
memoTotal += chunk.length
}
cb()
})
}, cb => {
contentStream.end(() => {
// TODO - stop modifying `opts`
opts.size = size
index.insert(cache, key, integrity, opts).then(entry => {
if (opts.memoize) {
memo.put(cache, entry, Buffer.concat(memoData, memoTotal), opts)
}
stream.emit('integrity', integrity)
cb()
})
})
})
let erred = false
stream.once('error', err => {
if (erred) { return }
erred = true
contentStream.emit('error', err)
})
contentStream.once('error', err => {
if (erred) { return }
erred = true
stream.emit('error', err)
})
return stream
}
+28
View File
@@ -0,0 +1,28 @@
'use strict'
const BB = require('bluebird')
const index = require('./lib/entry-index')
const memo = require('./lib/memoization')
const path = require('path')
const rimraf = BB.promisify(require('rimraf'))
const rmContent = require('./lib/content/rm')
module.exports = entry
module.exports.entry = entry
function entry (cache, key) {
memo.clearMemoized()
return index.delete(cache, key)
}
module.exports.content = content
function content (cache, integrity) {
memo.clearMemoized()
return rmContent(cache, integrity)
}
module.exports.all = all
function all (cache) {
memo.clearMemoized()
return rimraf(path.join(cache, '*(content-*|index-*)'))
}
+3
View File
@@ -0,0 +1,3 @@
'use strict'
module.exports = require('./lib/verify')
+34
View File
@@ -0,0 +1,34 @@
'use strict';
const path = require('path');
const commonDir = require('commondir');
const pkgDir = require('pkg-dir');
const makeDir = require('make-dir');
module.exports = options => {
const name = options.name;
let dir = options.cwd;
if (options.files) {
dir = commonDir(dir, options.files);
} else {
dir = dir || process.cwd();
}
dir = pkgDir.sync(dir);
if (dir) {
dir = path.join(dir, 'node_modules', '.cache', name);
if (dir && options.create) {
makeDir.sync(dir);
}
if (options.thunk) {
return function () {
return path.join.apply(path, [dir].concat(Array.prototype.slice.call(arguments)));
};
}
}
return dir;
};
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) James Talmage <james@talmage.io> (github.com/jamestalmage)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@@ -0,0 +1,79 @@
{
"_from": "find-cache-dir@^1.0.0",
"_id": "find-cache-dir@1.0.0",
"_inBundle": false,
"_integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=",
"_location": "/copy-webpack-plugin/find-cache-dir",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "find-cache-dir@^1.0.0",
"name": "find-cache-dir",
"escapedName": "find-cache-dir",
"rawSpec": "^1.0.0",
"saveSpec": null,
"fetchSpec": "^1.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin"
],
"_resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
"_shasum": "9288e3e9e3cc3748717d39eade17cf71fc30ee6f",
"_spec": "find-cache-dir@^1.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin",
"author": {
"name": "James Talmage",
"email": "james@talmage.io",
"url": "github.com/jamestalmage"
},
"bugs": {
"url": "https://github.com/avajs/find-cache-dir/issues"
},
"bundleDependencies": false,
"dependencies": {
"commondir": "^1.0.1",
"make-dir": "^1.0.0",
"pkg-dir": "^2.0.0"
},
"deprecated": false,
"description": "My well-made module",
"devDependencies": {
"ava": "^0.19.1",
"coveralls": "^2.11.6",
"del": "^2.2.2",
"nyc": "^10.3.2",
"xo": "^0.18.2"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/avajs/find-cache-dir#readme",
"keywords": [
"cache",
"directory",
"dir",
"caching",
"find",
"search"
],
"license": "MIT",
"name": "find-cache-dir",
"nyc": {
"reporter": [
"lcov",
"text"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/avajs/find-cache-dir.git"
},
"scripts": {
"test": "xo && nyc ava"
},
"version": "1.0.0"
}
+113
View File
@@ -0,0 +1,113 @@
# find-cache-dir [![Build Status](https://travis-ci.org/avajs/find-cache-dir.svg?branch=master)](https://travis-ci.org/avajs/find-cache-dir) [![Coverage Status](https://coveralls.io/repos/github/avajs/find-cache-dir/badge.svg?branch=master)](https://coveralls.io/github/avajs/find-cache-dir?branch=master)
> Finds the common standard cache directory
Recently the [`nyc`](https://github.com/bcoe/nyc) and [`AVA`](https://ava.li) projects decided to standardize on a common directory structure for storing cache information:
```sh
# nyc
./node_modules/.cache/nyc
# ava
./node_modules/.cache/ava
# your-module
./node_modules/.cache/your-module
```
This module makes it easy to correctly locate the cache directory according to this shared spec. If this pattern becomes ubiquitous, clearing the cache for multiple dependencies becomes easy and consistent:
```
rm -rf ./node_modules/.cache
```
If you decide to adopt this pattern, please file a PR adding your name to the list of adopters below.
## Install
```
$ npm install --save find-cache-dir
```
## Usage
```js
const findCacheDir = require('find-cache-dir');
findCacheDir({name: 'unicorns'});
//=> '/user/path/node-modules/.cache/unicorns'
```
## API
### findCacheDir([options])
Finds the cache directory using the supplied options. The algorithm tries to find a `package.json` file, searching every parent directory of the `cwd` specified (or implied from other options). It returns a `string` containing the absolute path to the cache directory, or `null` if `package.json` was never found.
#### options
##### name
*Required*<br>
Type: `string`
Should be the same as your project name in `package.json`.
##### files
Type: `Array` `string
An array of files that will be searched for a common parent directory. This common parent directory will be used in lieu of the `cwd` option below.
##### cwd
Type: `string`<br>
Default `process.cwd()`
Directory to start searching for a `package.json` from.
##### create
Type: `boolean`<br>
Default `false`
If `true`, the directory will be created synchronously before returning.
##### thunk
Type: `boolean`<br>
Default `false`
If `true`, this modifies the return type to be a function that is a thunk for `path.join(theFoundCacheDirectory)`.
```js
const thunk = findCacheDir({name: 'foo', thunk: true});
thunk();
//=> '/some/path/node_modules/.cache/foo'
thunk('bar.js')
//=> '/some/path/node_modules/.cache/foo/bar.js'
thunk('baz', 'quz.js')
//=> '/some/path/node_modules/.cache/foo/baz/quz.js'
```
This is helpful for actually putting actual files in the cache!
## Adopters
- [`AVA`](https://ava.li)
- [`nyc`](https://github.com/bcoe/nyc)
- [`babel-loader`](https://github.com/babel/babel-loader)
- [`eslint-loader`](https://github.com/MoOx/eslint-loader)
- [`Phenomic`](https://phenomic.io)
## License
MIT © [James Talmage](https://github.com/jamestalmage)
+48
View File
@@ -0,0 +1,48 @@
'use strict';
const path = require('path');
const locatePath = require('locate-path');
module.exports = (filename, opts) => {
opts = opts || {};
const startDir = path.resolve(opts.cwd || '');
const root = path.parse(startDir).root;
const filenames = [].concat(filename);
return new Promise(resolve => {
(function find(dir) {
locatePath(filenames, {cwd: dir}).then(file => {
if (file) {
resolve(path.join(dir, file));
} else if (dir === root) {
resolve(null);
} else {
find(path.dirname(dir));
}
});
})(startDir);
});
};
module.exports.sync = (filename, opts) => {
opts = opts || {};
let dir = path.resolve(opts.cwd || '');
const root = path.parse(dir).root;
const filenames = [].concat(filename);
// eslint-disable-next-line no-constant-condition
while (true) {
const file = locatePath.sync(filenames, {cwd: dir});
if (file) {
return path.join(dir, file);
} else if (dir === root) {
return null;
}
dir = path.dirname(dir);
}
};
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+85
View File
@@ -0,0 +1,85 @@
{
"_from": "find-up@^2.1.0",
"_id": "find-up@2.1.0",
"_inBundle": false,
"_integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"_location": "/copy-webpack-plugin/find-up",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "find-up@^2.1.0",
"name": "find-up",
"escapedName": "find-up",
"rawSpec": "^2.1.0",
"saveSpec": null,
"fetchSpec": "^2.1.0"
},
"_requiredBy": [
"/copy-webpack-plugin/pkg-dir"
],
"_resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"_shasum": "45d1b7e506c717ddd482775a2b77920a3c0c57a7",
"_spec": "find-up@^2.1.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\pkg-dir",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/find-up/issues"
},
"bundleDependencies": false,
"dependencies": {
"locate-path": "^2.0.0"
},
"deprecated": false,
"description": "Find a file by walking up parent directories",
"devDependencies": {
"ava": "*",
"tempfile": "^1.1.1",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/find-up#readme",
"keywords": [
"find",
"up",
"find-up",
"findup",
"look-up",
"look",
"file",
"search",
"match",
"package",
"resolve",
"parent",
"parents",
"folder",
"directory",
"dir",
"walk",
"walking",
"path"
],
"license": "MIT",
"name": "find-up",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/find-up.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "2.1.0",
"xo": {
"esnext": true
}
}
+85
View File
@@ -0,0 +1,85 @@
# find-up [![Build Status: Linux and macOS](https://travis-ci.org/sindresorhus/find-up.svg?branch=master)](https://travis-ci.org/sindresorhus/find-up) [![Build Status: Windows](https://ci.appveyor.com/api/projects/status/l0cyjmvh5lq72vq2/branch/master?svg=true)](https://ci.appveyor.com/project/sindresorhus/find-up/branch/master)
> Find a file by walking up parent directories
## Install
```
$ npm install --save find-up
```
## Usage
```
/
└── Users
└── sindresorhus
├── unicorn.png
└── foo
└── bar
├── baz
└── example.js
```
```js
// example.js
const findUp = require('find-up');
findUp('unicorn.png').then(filepath => {
console.log(filepath);
//=> '/Users/sindresorhus/unicorn.png'
});
findUp(['rainbow.png', 'unicorn.png']).then(filepath => {
console.log(filepath);
//=> '/Users/sindresorhus/unicorn.png'
});
```
## API
### findUp(filename, [options])
Returns a `Promise` for the filepath or `null`.
### findUp([filenameA, filenameB], [options])
Returns a `Promise` for the first filepath found (by respecting the order) or `null`.
### findUp.sync(filename, [options])
Returns a filepath or `null`.
### findUp.sync([filenameA, filenameB], [options])
Returns the first filepath found (by respecting the order) or `null`.
#### filename
Type: `string`
Filename of the file to find.
#### options
##### cwd
Type: `string`<br>
Default: `process.cwd()`
Directory to start from.
## Related
- [find-up-cli](https://github.com/sindresorhus/find-up-cli) - CLI for this module
- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
- [pkg-dir](https://github.com/sindresorhus/pkg-dir) - Find the root directory of an npm package
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+88
View File
@@ -0,0 +1,88 @@
'use strict';
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const gitIgnore = require('ignore');
const pify = require('pify');
const slash = require('slash');
const globP = pify(glob);
const readFileP = pify(fs.readFile);
const mapGitIgnorePatternTo = base => ignore => {
if (ignore.startsWith('!')) {
return '!' + path.posix.join(base, ignore.substr(1));
}
return path.posix.join(base, ignore);
};
const parseGitIgnore = (content, opts) => {
const base = slash(path.relative(opts.cwd, path.dirname(opts.fileName)));
return content
.split(/\r?\n/)
.filter(Boolean)
.filter(l => l.charAt(0) !== '#')
.map(mapGitIgnorePatternTo(base));
};
const reduceIgnore = files => {
return files.reduce((ignores, file) => {
ignores.add(parseGitIgnore(file.content, {
cwd: file.cwd,
fileName: file.filePath
}));
return ignores;
}, gitIgnore());
};
const getIsIgnoredPredecate = (ignores, cwd) => {
return p => ignores.ignores(slash(path.relative(cwd, p)));
};
const getFile = (file, cwd) => {
const filePath = path.join(cwd, file);
return readFileP(filePath, 'utf8')
.then(content => ({
content,
cwd,
filePath
}));
};
const getFileSync = (file, cwd) => {
const filePath = path.join(cwd, file);
const content = fs.readFileSync(filePath, 'utf8');
return {
content,
cwd,
filePath
};
};
const normalizeOpts = opts => {
opts = opts || {};
const ignore = opts.ignore || [];
const cwd = opts.cwd || process.cwd();
return {ignore, cwd};
};
module.exports = o => {
const opts = normalizeOpts(o);
return globP('**/.gitignore', {ignore: opts.ignore, cwd: opts.cwd})
.then(paths => Promise.all(paths.map(file => getFile(file, opts.cwd))))
.then(files => reduceIgnore(files))
.then(ignores => getIsIgnoredPredecate(ignores, opts.cwd));
};
module.exports.sync = o => {
const opts = normalizeOpts(o);
const paths = glob.sync('**/.gitignore', {ignore: opts.ignore, cwd: opts.cwd});
const files = paths.map(file => getFileSync(file, opts.cwd));
const ignores = reduceIgnore(files);
return getIsIgnoredPredecate(ignores, opts.cwd);
};
+134
View File
@@ -0,0 +1,134 @@
'use strict';
const arrayUnion = require('array-union');
const glob = require('glob');
const pify = require('pify');
const dirGlob = require('dir-glob');
const gitignore = require('./gitignore');
const globP = pify(glob);
const DEFAULT_FILTER = () => false;
const isNegative = pattern => pattern[0] === '!';
const assertPatternsInput = patterns => {
if (!patterns.every(x => typeof x === 'string')) {
throw new TypeError('Patterns must be a string or an array of strings');
}
};
const generateGlobTasks = (patterns, taskOpts) => {
patterns = [].concat(patterns);
assertPatternsInput(patterns);
const globTasks = [];
taskOpts = Object.assign({
cache: Object.create(null),
statCache: Object.create(null),
realpathCache: Object.create(null),
symlinks: Object.create(null),
ignore: [],
expandDirectories: true,
nodir: true
}, taskOpts);
patterns.forEach((pattern, i) => {
if (isNegative(pattern)) {
return;
}
const ignore = patterns
.slice(i)
.filter(isNegative)
.map(pattern => pattern.slice(1));
const opts = Object.assign({}, taskOpts, {
ignore: taskOpts.ignore.concat(ignore)
});
globTasks.push({pattern, opts});
});
return globTasks;
};
const globDirs = (task, fn) => {
if (Array.isArray(task.opts.expandDirectories)) {
return fn(task.pattern, {files: task.opts.expandDirectories});
}
if (typeof task.opts.expandDirectories === 'object') {
return fn(task.pattern, task.opts.expandDirectories);
}
return fn(task.pattern);
};
const getPattern = (task, fn) => task.opts.expandDirectories ? globDirs(task, fn) : [task.pattern];
module.exports = (patterns, opts) => {
let globTasks;
try {
globTasks = generateGlobTasks(patterns, opts);
} catch (err) {
return Promise.reject(err);
}
const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob))
.then(globs => Promise.all(globs.map(glob => ({
pattern: glob,
opts: task.opts
}))))
))
.then(tasks => arrayUnion.apply(null, tasks));
const getFilter = () => {
return Promise.resolve(
opts && opts.gitignore ?
gitignore({cwd: opts.cwd, ignore: opts.ignore}) :
DEFAULT_FILTER
);
};
return getFilter()
.then(filter => {
return getTasks
.then(tasks => Promise.all(tasks.map(task => globP(task.pattern, task.opts))))
.then(paths => arrayUnion.apply(null, paths))
.then(paths => paths.filter(p => !filter(p)));
});
};
module.exports.sync = (patterns, opts) => {
const globTasks = generateGlobTasks(patterns, opts);
const getFilter = () => {
return opts && opts.gitignore ?
gitignore.sync({cwd: opts.cwd, ignore: opts.ignore}) :
DEFAULT_FILTER;
};
const tasks = globTasks.reduce((tasks, task) => {
const newTask = getPattern(task, dirGlob.sync).map(glob => ({
pattern: glob,
opts: task.opts
}));
return tasks.concat(newTask);
}, []);
const filter = getFilter();
return tasks.reduce(
(matches, task) => arrayUnion(matches, glob.sync(task.pattern, task.opts)),
[]
).filter(p => !filter(p));
};
module.exports.generateGlobTasks = generateGlobTasks;
module.exports.hasMagic = (patterns, opts) => []
.concat(patterns)
.some(pattern => glob.hasMagic(pattern, opts));
module.exports.gitignore = gitignore;
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+106
View File
@@ -0,0 +1,106 @@
{
"_from": "globby@^7.1.1",
"_id": "globby@7.1.1",
"_inBundle": false,
"_integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
"_location": "/copy-webpack-plugin/globby",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "globby@^7.1.1",
"name": "globby",
"escapedName": "globby",
"rawSpec": "^7.1.1",
"saveSpec": null,
"fetchSpec": "^7.1.1"
},
"_requiredBy": [
"/copy-webpack-plugin"
],
"_resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
"_shasum": "fb2ccff9401f8600945dfada97440cca972b8680",
"_spec": "globby@^7.1.1",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/globby/issues"
},
"bundleDependencies": false,
"dependencies": {
"array-union": "^1.0.1",
"dir-glob": "^2.0.0",
"glob": "^7.1.2",
"ignore": "^3.3.5",
"pify": "^3.0.0",
"slash": "^1.0.0"
},
"deprecated": false,
"description": "Extends `glob` with support for multiple patterns and exposes a Promise API",
"devDependencies": {
"ava": "*",
"fast-glob": "^1.0.1",
"glob-stream": "^6.1.0",
"globby": "github:sindresorhus/globby#master",
"matcha": "^0.7.0",
"rimraf": "^2.2.8",
"xo": "^0.18.0"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js",
"gitignore.js"
],
"homepage": "https://github.com/sindresorhus/globby#readme",
"keywords": [
"all",
"array",
"directories",
"dirs",
"expand",
"files",
"filesystem",
"filter",
"find",
"fnmatch",
"folders",
"fs",
"glob",
"globbing",
"globs",
"gulpfriendly",
"match",
"matcher",
"minimatch",
"multi",
"multiple",
"paths",
"pattern",
"patterns",
"traverse",
"util",
"utility",
"wildcard",
"wildcards",
"promise",
"gitignore",
"git"
],
"license": "MIT",
"name": "globby",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/globby.git"
},
"scripts": {
"bench": "npm update glob-stream fast-glob && matcha bench.js",
"test": "xo && ava"
},
"version": "7.1.1"
}
+156
View File
@@ -0,0 +1,156 @@
# globby [![Build Status](https://travis-ci.org/sindresorhus/globby.svg?branch=master)](https://travis-ci.org/sindresorhus/globby)
> User-friendly glob matching
Based on [`glob`](https://github.com/isaacs/node-glob), but adds a bunch of useful features and a nicer API.
## Features
- Promise API
- Multiple patterns
- Negated patterns: `['foo*', '!foobar']`
- Expands directories: `dir` → `dir/**/*`
- Supports `.gitignore`
## Install
```
$ npm install globby
```
## Usage
```
├── unicorn
├── cake
└── rainbow
```
```js
const globby = require('globby');
(async () => {
const paths = await globby(['*', '!cake']);
console.log(paths);
//=> ['unicorn', 'rainbow']
})();
```
## API
### globby(patterns, [options])
Returns a `Promise<Array>` of matching paths.
#### patterns
Type: `string` `Array`
See supported `minimatch` [patterns](https://github.com/isaacs/minimatch#usage).
#### options
Type: `Object`
See the [`node-glob` options](https://github.com/isaacs/node-glob#options) in addition to the ones below.
One difference is that `nodir` is `true` by default here.
##### expandDirectories
Type: `boolean` `Array` `Object`<br>
Default: `true`
If set to `true`, `globby` will automatically glob directories for you. If you define an `Array` it will only glob files that matches the patterns inside the `Array`. You can also define an `Object` with `files` and `extensions` like below:
```js
(async () => {
const paths = await globby('images', {
expandDirectories: {
files: ['cat', 'unicorn', '*.jpg'],
extensions: ['png']
}
});
console.log(paths);
//=> ['cat.png', 'unicorn.png', 'cow.jpg', 'rainbow.jpg']
})();
```
Note that if you set this option to `false`, you won't get back matched directories unless you set `nodir: false`.
##### gitignore
Type: `boolean`<br>
Default: `false`
Respect ignore patterns in `.gitignore` files that apply to the globbed files.
### globby.sync(patterns, [options])
Returns an `Array` of matching paths.
### globby.generateGlobTasks(patterns, [options])
Returns an `Array<Object>` in the format `{pattern: string, opts: Object}`, which can be passed as arguments to [`node-glob`](https://github.com/isaacs/node-glob). This is useful for other globbing-related packages.
Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, run this method each time to ensure file system changes are taken into consideration.
### globby.hasMagic(patterns, [options])
Returns a `boolean` of whether there are any special glob characters in the `patterns`.
Note that the options affect the results. If `noext: true` is set, then `+(a|b)` will not be considered a magic pattern. If the pattern has a brace expansion, like `a/{b/c,x/y}`, then that is considered magical, unless `nobrace: true` is set.
### globby.gitignore([options])
Returns a `Promise<(path: string) => boolean>` indicating wether a given path is ignored via a `.gitignore` file.
Takes `cwd?: string` and `ignore?: string[]` as options. `.gitignore` files matched by the ignore config are not
used for the resulting filter function.
```js
const {gitignore} = require('globby');
(async () => {
const isIgnored = await gitignore();
console.log(isIgnored('some/file'));
})();
```
### globby.gitignore.sync([options])
Returns a `(path: string) => boolean` indicating wether a given path is ignored via a `.gitignore` file.
Takes the same options as `globby.gitignore`.
## Globbing patterns
Just a quick overview.
- `*` matches any number of characters, but not `/`
- `?` matches a single character, but not `/`
- `**` matches any number of characters, including `/`, as long as it's the only thing in a path part
- `{}` allows for a comma-separated list of "or" expressions
- `!` at the beginning of a pattern will negate the match
[Various patterns and expected matches.](https://github.com/sindresorhus/multimatch/blob/master/test/test.js)
## Related
- [multimatch](https://github.com/sindresorhus/multimatch) - Match against a list instead of the filesystem
- [matcher](https://github.com/sindresorhus/matcher) - Simple wildcard matching
- [del](https://github.com/sindresorhus/del) - Delete files and directories
- [make-dir](https://github.com/sindresorhus/make-dir) - Make a directory and its parents if needed
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+24
View File
@@ -0,0 +1,24 @@
'use strict';
const path = require('path');
const pathExists = require('path-exists');
const pLocate = require('p-locate');
module.exports = (iterable, opts) => {
opts = Object.assign({
cwd: process.cwd()
}, opts);
return pLocate(iterable, el => pathExists(path.resolve(opts.cwd, el)), opts);
};
module.exports.sync = (iterable, opts) => {
opts = Object.assign({
cwd: process.cwd()
}, opts);
for (const el of iterable) {
if (pathExists.sync(path.resolve(opts.cwd, el))) {
return el;
}
}
};
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+79
View File
@@ -0,0 +1,79 @@
{
"_from": "locate-path@^2.0.0",
"_id": "locate-path@2.0.0",
"_inBundle": false,
"_integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"_location": "/copy-webpack-plugin/locate-path",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "locate-path@^2.0.0",
"name": "locate-path",
"escapedName": "locate-path",
"rawSpec": "^2.0.0",
"saveSpec": null,
"fetchSpec": "^2.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/find-up"
],
"_resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"_shasum": "2b568b265eec944c6d9c0de9c3dbbbca0354cd8e",
"_spec": "locate-path@^2.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\find-up",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/locate-path/issues"
},
"bundleDependencies": false,
"dependencies": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
},
"deprecated": false,
"description": "Get the first path that exists on disk of multiple paths",
"devDependencies": {
"ava": "*",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/locate-path#readme",
"keywords": [
"locate",
"path",
"paths",
"file",
"files",
"exists",
"find",
"finder",
"search",
"searcher",
"array",
"iterable",
"iterator"
],
"license": "MIT",
"name": "locate-path",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/locate-path.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "2.0.0",
"xo": {
"esnext": true
}
}
+99
View File
@@ -0,0 +1,99 @@
# locate-path [![Build Status](https://travis-ci.org/sindresorhus/locate-path.svg?branch=master)](https://travis-ci.org/sindresorhus/locate-path)
> Get the first path that exists on disk of multiple paths
## Install
```
$ npm install --save locate-path
```
## Usage
Here we find the first file that exists on disk, in array order.
```js
const locatePath = require('locate-path');
const files = [
'unicorn.png',
'rainbow.png', // only this one actually exists on disk
'pony.png'
];
locatePath(files).then(foundPath => {
console.log(foundPath);
//=> 'rainbow'
});
```
## API
### locatePath(input, [options])
Returns a `Promise` for the first path that exists or `undefined` if none exists.
#### input
Type: `Iterable<string>`
Paths to check.
#### options
Type: `Object`
##### concurrency
Type: `number`<br>
Default: `Infinity`<br>
Minimum: `1`
Number of concurrently pending promises.
##### preserveOrder
Type: `boolean`<br>
Default: `true`
Preserve `input` order when searching.
Disable this to improve performance if you don't care about the order.
##### cwd
Type: `string`<br>
Default: `process.cwd()`
Current working directory.
### locatePath.sync(input, [options])
Returns the first path that exists or `undefined` if none exists.
#### input
Type: `Iterable<string>`
Paths to check.
#### options
Type: `Object`
##### cwd
Same as above.
## Related
- [path-exists](https://github.com/sindresorhus/path-exists) - Check if a path exists
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+15
View File
@@ -0,0 +1,15 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+158
View File
@@ -0,0 +1,158 @@
# 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
+468
View File
@@ -0,0 +1,468 @@
'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
}
+71
View File
@@ -0,0 +1,71 @@
{
"_from": "lru-cache@^4.1.1",
"_id": "lru-cache@4.1.5",
"_inBundle": false,
"_integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"_location": "/copy-webpack-plugin/lru-cache",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "lru-cache@^4.1.1",
"name": "lru-cache",
"escapedName": "lru-cache",
"rawSpec": "^4.1.1",
"saveSpec": null,
"fetchSpec": "^4.1.1"
},
"_requiredBy": [
"/copy-webpack-plugin/cacache"
],
"_resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"_shasum": "8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd",
"_spec": "lru-cache@^4.1.1",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\cacache",
"author": {
"name": "Isaac Z. Schlueter",
"email": "i@izs.me"
},
"bugs": {
"url": "https://github.com/isaacs/node-lru-cache/issues"
},
"bundleDependencies": false,
"dependencies": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
},
"deprecated": false,
"description": "A cache object that deletes the least-recently-used items.",
"devDependencies": {
"benchmark": "^2.1.4",
"standard": "^12.0.1",
"tap": "^12.1.0"
},
"files": [
"index.js"
],
"homepage": "https://github.com/isaacs/node-lru-cache#readme",
"keywords": [
"mru",
"lru",
"cache"
],
"license": "ISC",
"main": "index.js",
"name": "lru-cache",
"repository": {
"type": "git",
"url": "git://github.com/isaacs/node-lru-cache.git"
},
"scripts": {
"coveragerport": "tap --coverage-report=html",
"lintfix": "standard --fix test/*.js index.js",
"postpublish": "git push origin --all; git push origin --tags",
"posttest": "standard test/*.js index.js",
"postversion": "npm publish --tag=legacy",
"preversion": "npm test",
"snap": "TAP_SNAPSHOT=1 tap test/*.js -J",
"test": "tap test/*.js --100 -J"
},
"version": "4.1.5"
}
+85
View File
@@ -0,0 +1,85 @@
'use strict';
const fs = require('fs');
const path = require('path');
const pify = require('pify');
const defaults = {
mode: 0o777 & (~process.umask()),
fs
};
// https://github.com/nodejs/node/issues/8987
// https://github.com/libuv/libuv/pull/1088
const checkPath = pth => {
if (process.platform === 'win32') {
const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, ''));
if (pathHasInvalidWinCharacters) {
const err = new Error(`Path contains invalid characters: ${pth}`);
err.code = 'EINVAL';
throw err;
}
}
};
module.exports = (input, opts) => Promise.resolve().then(() => {
checkPath(input);
opts = Object.assign({}, defaults, opts);
const mkdir = pify(opts.fs.mkdir);
const stat = pify(opts.fs.stat);
const make = pth => {
return mkdir(pth, opts.mode)
.then(() => pth)
.catch(err => {
if (err.code === 'ENOENT') {
if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
throw err;
}
return make(path.dirname(pth)).then(() => make(pth));
}
return stat(pth)
.then(stats => stats.isDirectory() ? pth : Promise.reject())
.catch(() => {
throw err;
});
});
};
return make(path.resolve(input));
});
module.exports.sync = (input, opts) => {
checkPath(input);
opts = Object.assign({}, defaults, opts);
const make = pth => {
try {
opts.fs.mkdirSync(pth, opts.mode);
} catch (err) {
if (err.code === 'ENOENT') {
if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
throw err;
}
make(path.dirname(pth));
return make(pth);
}
try {
if (!opts.fs.statSync(pth).isDirectory()) {
throw new Error('The path is not a directory');
}
} catch (_) {
throw err;
}
}
return pth;
};
return make(path.resolve(input));
};
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+86
View File
@@ -0,0 +1,86 @@
{
"_from": "make-dir@^1.0.0",
"_id": "make-dir@1.3.0",
"_inBundle": false,
"_integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"_location": "/copy-webpack-plugin/make-dir",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "make-dir@^1.0.0",
"name": "make-dir",
"escapedName": "make-dir",
"rawSpec": "^1.0.0",
"saveSpec": null,
"fetchSpec": "^1.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/find-cache-dir"
],
"_resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"_shasum": "79c1033b80515bd6d24ec9933e860ca75ee27f0c",
"_spec": "make-dir@^1.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\find-cache-dir",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/make-dir/issues"
},
"bundleDependencies": false,
"dependencies": {
"pify": "^3.0.0"
},
"deprecated": false,
"description": "Make a directory and its parents if needed - Think `mkdir -p`",
"devDependencies": {
"ava": "*",
"codecov": "^3.0.0",
"graceful-fs": "^4.1.11",
"nyc": "^11.3.0",
"path-type": "^3.0.0",
"tempy": "^0.2.1",
"xo": "^0.20.0"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/make-dir#readme",
"keywords": [
"mkdir",
"mkdirp",
"make",
"directories",
"dir",
"dirs",
"folders",
"directory",
"folder",
"path",
"parent",
"parents",
"intermediate",
"recursively",
"recursive",
"create",
"fs",
"filesystem",
"file-system"
],
"license": "MIT",
"name": "make-dir",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/make-dir.git"
},
"scripts": {
"test": "xo && nyc ava"
},
"version": "1.3.0"
}
+116
View File
@@ -0,0 +1,116 @@
# make-dir [![Build Status: macOS & Linux](https://travis-ci.org/sindresorhus/make-dir.svg?branch=master)](https://travis-ci.org/sindresorhus/make-dir) [![Build status: Windows](https://ci.appveyor.com/api/projects/status/e0vtt8y600w91gcs/branch/master?svg=true)](https://ci.appveyor.com/project/sindresorhus/make-dir/branch/master) [![codecov](https://codecov.io/gh/sindresorhus/make-dir/branch/master/graph/badge.svg)](https://codecov.io/gh/sindresorhus/make-dir)
> Make a directory and its parents if needed - Think `mkdir -p`
## Advantages over [`mkdirp`](https://github.com/substack/node-mkdirp)
- Promise API *(Async/await ready!)*
- Fixes many `mkdirp` issues: [#96](https://github.com/substack/node-mkdirp/pull/96) [#70](https://github.com/substack/node-mkdirp/issues/70) [#66](https://github.com/substack/node-mkdirp/issues/66)
- 100% test coverage
- CI-tested on macOS, Linux, and Windows
- Actively maintained
- Doesn't bundle a CLI
## Install
```
$ npm install make-dir
```
## Usage
```
$ pwd
/Users/sindresorhus/fun
$ tree
.
```
```js
const makeDir = require('make-dir');
makeDir('unicorn/rainbow/cake').then(path => {
console.log(path);
//=> '/Users/sindresorhus/fun/unicorn/rainbow/cake'
});
```
```
$ tree
.
└── unicorn
└── rainbow
└── cake
```
Multiple directories:
```js
const makeDir = require('make-dir');
Promise.all([
makeDir('unicorn/rainbow')
makeDir('foo/bar')
]).then(paths => {
console.log(paths);
/*
[
'/Users/sindresorhus/fun/unicorn/rainbow',
'/Users/sindresorhus/fun/foo/bar'
]
*/
});
```
## API
### makeDir(path, [options])
Returns a `Promise` for the path to the created directory.
### makeDir.sync(path, [options])
Returns the path to the created directory.
#### path
Type: `string`
Directory to create.
#### options
Type: `Object`
##### mode
Type: `integer`<br>
Default: `0o777 & (~process.umask())`
Directory [permissions](https://x-team.com/blog/file-system-permissions-umask-node-js/).
##### fs
Type: `Object`<br>
Default: `require('fs')`
Use a custom `fs` implementation. For example [`graceful-fs`](https://github.com/isaacs/node-graceful-fs).
## Related
- [make-dir-cli](https://github.com/sindresorhus/make-dir-cli) - CLI for this module
- [del](https://github.com/sindresorhus/del) - Delete files and directories
- [globby](https://github.com/sindresorhus/globby) - User-friendly glob matching
- [cpy](https://github.com/sindresorhus/cpy) - Copy files
- [cpy-cli](https://github.com/sindresorhus/cpy-cli) - Copy files on the command-line
- [move-file](https://github.com/sindresorhus/move-file) - Move a file
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
@@ -0,0 +1,7 @@
# mississippi Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 2.0.0 - 2018-01-30
* Update to pump@2.0.1. (Use the individual modules to avoid potentially unnecessary major updates in your project)
* Pin engines support to >= Node 4.0.0. Run Node LTS or greater.
+10
View File
@@ -0,0 +1,10 @@
module.exports.pipe = require('pump')
module.exports.each = require('stream-each')
module.exports.pipeline = require('pumpify')
module.exports.duplex = require('duplexify')
module.exports.through = require('through2')
module.exports.concat = require('concat-stream')
module.exports.finished = require('end-of-stream')
module.exports.from = require('from2')
module.exports.to = require('flush-write-stream')
module.exports.parallel = require('parallel-transform')
+7
View File
@@ -0,0 +1,7 @@
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+62
View File
@@ -0,0 +1,62 @@
{
"_from": "mississippi@^2.0.0",
"_id": "mississippi@2.0.0",
"_inBundle": false,
"_integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==",
"_location": "/copy-webpack-plugin/mississippi",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "mississippi@^2.0.0",
"name": "mississippi",
"escapedName": "mississippi",
"rawSpec": "^2.0.0",
"saveSpec": null,
"fetchSpec": "^2.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/cacache"
],
"_resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz",
"_shasum": "3442a508fafc28500486feea99409676e4ee5a6f",
"_spec": "mississippi@^2.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\cacache",
"author": {
"name": "max ogden"
},
"bugs": {
"url": "https://github.com/maxogden/mississippi/issues"
},
"bundleDependencies": false,
"dependencies": {
"concat-stream": "^1.5.0",
"duplexify": "^3.4.2",
"end-of-stream": "^1.1.0",
"flush-write-stream": "^1.0.0",
"from2": "^2.1.0",
"parallel-transform": "^1.1.0",
"pump": "^2.0.1",
"pumpify": "^1.3.3",
"stream-each": "^1.1.0",
"through2": "^2.0.0"
},
"deprecated": false,
"description": "a collection of useful streams",
"devDependencies": {},
"engines": {
"node": ">=4.0.0"
},
"homepage": "https://github.com/maxogden/mississippi#readme",
"license": "BSD-2-Clause",
"main": "index.js",
"name": "mississippi",
"repository": {
"type": "git",
"url": "git+https://github.com/maxogden/mississippi.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "2.0.0"
}
+411
View File
@@ -0,0 +1,411 @@
# mississippi
a collection of useful stream utility modules. learn how the modules work using this and then pick the ones you want and use them individually
the goal of the modules included in mississippi is to make working with streams easy without sacrificing speed, error handling or composability.
## usage
```js
var miss = require('mississippi')
```
## methods
- [pipe](#pipe)
- [each](#each)
- [pipeline](#pipeline)
- [duplex](#duplex)
- [through](#through)
- [from](#from)
- [to](#to)
- [concat](#concat)
- [finished](#finished)
- [parallel](#parallel)
### pipe
##### `miss.pipe(stream1, stream2, stream3, ..., cb)`
Pipes streams together and destroys all of them if one of them closes. Calls `cb` with `(error)` if there was an error in any of the streams.
When using standard `source.pipe(destination)` the source will _not_ be destroyed if the destination emits close or error. You are also not able to provide a callback to tell when the pipe has finished.
`miss.pipe` does these two things for you, ensuring you handle stream errors 100% of the time (unhandled errors are probably the most common bug in most node streams code)
#### original module
`miss.pipe` is provided by [`require('pump')`](https://www.npmjs.com/package/pump)
#### example
```js
// lets do a simple file copy
var fs = require('fs')
var read = fs.createReadStream('./original.zip')
var write = fs.createWriteStream('./copy.zip')
// use miss.pipe instead of read.pipe(write)
miss.pipe(read, write, function (err) {
if (err) return console.error('Copy error!', err)
console.log('Copied successfully')
})
```
### each
##### `miss.each(stream, each, [done])`
Iterate the data in `stream` one chunk at a time. Your `each` function will be called with `(data, next)` where data is a data chunk and next is a callback. Call `next` when you are ready to consume the next chunk.
Optionally you can call `next` with an error to destroy the stream. You can also pass the optional third argument, `done`, which is a function that will be called with `(err)` when the stream ends. The `err` argument will be populated with an error if the stream emitted an error.
#### original module
`miss.each` is provided by [`require('stream-each')`](https://www.npmjs.com/package/stream-each)
#### example
```js
var fs = require('fs')
var split = require('split2')
var newLineSeparatedNumbers = fs.createReadStream('numbers.txt')
var pipeline = miss.pipeline(newLineSeparatedNumbers, split())
miss.each(pipeline, eachLine, done)
var sum = 0
function eachLine (line, next) {
sum += parseInt(line.toString())
next()
}
function done (err) {
if (err) throw err
console.log('sum is', sum)
}
```
### pipeline
##### `var pipeline = miss.pipeline(stream1, stream2, stream3, ...)`
Builds a pipeline from all the transform streams passed in as arguments by piping them together and returning a single stream object that lets you write to the first stream and read from the last stream.
If you are pumping object streams together use `pipeline = miss.pipeline.obj(s1, s2, ...)`.
If any of the streams in the pipeline emits an error or gets destroyed, or you destroy the stream it returns, all of the streams will be destroyed and cleaned up for you.
#### original module
`miss.pipeline` is provided by [`require('pumpify')`](https://www.npmjs.com/package/pumpify)
#### example
```js
// first create some transform streams (note: these two modules are fictional)
var imageResize = require('image-resizer-stream')({width: 400})
var pngOptimizer = require('png-optimizer-stream')({quality: 60})
// instead of doing a.pipe(b), use pipelin
var resizeAndOptimize = miss.pipeline(imageResize, pngOptimizer)
// `resizeAndOptimize` is a transform stream. when you write to it, it writes
// to `imageResize`. when you read from it, it reads from `pngOptimizer`.
// it handles piping all the streams together for you
// use it like any other transform stream
var fs = require('fs')
var read = fs.createReadStream('./image.png')
var write = fs.createWriteStream('./resized-and-optimized.png')
miss.pipe(read, resizeAndOptimize, write, function (err) {
if (err) return console.error('Image processing error!', err)
console.log('Image processed successfully')
})
```
### duplex
##### `var duplex = miss.duplex([writable, readable, opts])`
Take two separate streams, a writable and a readable, and turn them into a single [duplex (readable and writable) stream](https://nodejs.org/api/stream.html#stream_class_stream_duplex).
The returned stream will emit data from the readable. When you write to it it writes to the writable.
You can either choose to supply the writable and the readable at the time you create the stream, or you can do it later using the `.setWritable` and `.setReadable` methods and data written to the stream in the meantime will be buffered for you.
#### original module
`miss.duplex` is provided by [`require('duplexify')`](https://www.npmjs.com/package/duplexify)
#### example
```js
// lets spawn a process and take its stdout and stdin and combine them into 1 stream
var child = require('child_process')
// @- tells it to read from stdin, --data-binary sets 'raw' binary mode
var curl = child.spawn('curl -X POST --data-binary @- http://foo.com')
// duplexCurl will write to stdin and read from stdout
var duplexCurl = miss.duplex(curl.stdin, curl.stdout)
```
### through
##### `var transformer = miss.through([options, transformFunction, flushFunction])`
Make a custom [transform stream](https://nodejs.org/docs/latest/api/stream.html#stream_class_stream_transform).
The `options` object is passed to the internal transform stream and can be used to create an `objectMode` stream (or use the shortcut `miss.through.obj([...])`)
The `transformFunction` is called when data is available for the writable side and has the signature `(chunk, encoding, cb)`. Within the function, add data to the readable side any number of times with `this.push(data)`. Call `cb()` to indicate processing of the `chunk` is complete. Or to easily emit a single error or chunk, call `cb(err, chunk)`
The `flushFunction`, with signature `(cb)`, is called just before the stream is complete and should be used to wrap up stream processing.
#### original module
`miss.through` is provided by [`require('through2')`](https://www.npmjs.com/package/through2)
#### example
```js
var fs = require('fs')
var read = fs.createReadStream('./boring_lowercase.txt')
var write = fs.createWriteStream('./AWESOMECASE.TXT')
// Leaving out the options object
var uppercaser = miss.through(
function (chunk, enc, cb) {
cb(null, chunk.toString().toUpperCase())
},
function (cb) {
cb(null, 'ONE LAST BIT OF UPPERCASE')
}
)
miss.pipe(read, uppercaser, write, function (err) {
if (err) return console.error('Trouble uppercasing!')
console.log('Splendid uppercasing!')
})
```
### from
##### `miss.from([opts], read)`
Make a custom [readable stream](https://nodejs.org/docs/latest/api/stream.html#stream_class_stream_readable).
`opts` contains the options to pass on to the ReadableStream constructor e.g. for creating a readable object stream (or use the shortcut `miss.from.obj([...])`).
Returns a readable stream that calls `read(size, next)` when data is requested from the stream.
- `size` is the recommended amount of data (in bytes) to retrieve.
- `next(err, chunk)` should be called when you're ready to emit more data.
#### original module
`miss.from` is provided by [`require('from2')`](https://www.npmjs.com/package/from2)
#### example
```js
function fromString(string) {
return miss.from(function(size, next) {
// if there's no more content
// left in the string, close the stream.
if (string.length <= 0) return next(null, null)
// Pull in a new chunk of text,
// removing it from the string.
var chunk = string.slice(0, size)
string = string.slice(size)
// Emit "chunk" from the stream.
next(null, chunk)
})
}
// pipe "hello world" out
// to stdout.
fromString('hello world').pipe(process.stdout)
```
### to
##### `miss.to([options], write, [flush])`
Make a custom [writable stream](https://nodejs.org/docs/latest/api/stream.html#stream_class_stream_writable).
`opts` contains the options to pass on to the WritableStream constructor e.g. for creating a writable object stream (or use the shortcut `miss.to.obj([...])`).
Returns a writable stream that calls `write(data, enc, cb)` when data is written to the stream.
- `data` is the received data to write the destination.
- `enc` encoding of the piece of data received.
- `cb(err, data)` should be called when you're ready to write more data, or encountered an error.
`flush(cb)` is called before `finish` is emitted and allows for cleanup steps to occur.
#### original module
`miss.to` is provided by [`require('flush-write-stream')`](https://www.npmjs.com/package/flush-write-stream)
#### example
```js
var ws = miss.to(write, flush)
ws.on('finish', function () {
console.log('finished')
})
ws.write('hello')
ws.write('world')
ws.end()
function write (data, enc, cb) {
// i am your normal ._write method
console.log('writing', data.toString())
cb()
}
function flush (cb) {
// i am called before finish is emitted
setTimeout(cb, 1000) // wait 1 sec
}
```
If you run the above it will produce the following output
```
writing hello
writing world
(nothing happens for 1 sec)
finished
```
### concat
##### `var concat = miss.concat(cb)`
Returns a writable stream that concatenates all data written to the stream and calls a callback with the single result.
Calling `miss.concat(cb)` returns a writable stream. `cb` is called when the writable stream is finished, e.g. when all data is done being written to it. `cb` is called with a single argument, `(data)`, which will contain the result of concatenating all the data written to the stream.
Note that `miss.concat` will not handle stream errors for you. To handle errors, use `miss.pipe` or handle the `error` event manually.
#### original module
`miss.concat` is provided by [`require('concat-stream')`](https://www.npmjs.com/package/concat-stream)
#### example
```js
var fs = require('fs')
var readStream = fs.createReadStream('cat.png')
var concatStream = miss.concat(gotPicture)
function callback (err) {
if (err) {
console.error(err)
process.exit(1)
}
}
miss.pipe(readStream, concatStream, callback)
function gotPicture(imageBuffer) {
// imageBuffer is all of `cat.png` as a node.js Buffer
}
function handleError(err) {
// handle your error appropriately here, e.g.:
console.error(err) // print the error to STDERR
process.exit(1) // exit program with non-zero exit code
}
```
### finished
##### `miss.finished(stream, cb)`
Waits for `stream` to finish or error and then calls `cb` with `(err)`. `cb` will only be called once. `err` will be null if the stream finished without error, or else it will be populated with the error from the streams `error` event.
This function is useful for simplifying stream handling code as it lets you handle success or error conditions in a single code path. It's used internally `miss.pipe`.
#### original module
`miss.finished` is provided by [`require('end-of-stream')`](https://www.npmjs.com/package/end-of-stream)
#### example
```js
var copySource = fs.createReadStream('./movie.mp4')
var copyDest = fs.createWriteStream('./movie-copy.mp4')
copySource.pipe(copyDest)
miss.finished(copyDest, function(err) {
if (err) return console.log('write failed', err)
console.log('write success')
})
```
### parallel
##### `miss.parallel(concurrency, each)`
This works like `through` except you can process items in parallel, while still preserving the original input order.
This is handy if you wanna take advantage of node's async I/O and process streams of items in batches. With this module you can build your very own streaming parallel job queue.
Note that `miss.parallel` preserves input ordering, if you don't need that then you can use [through2-concurrent](https://github.com/almost/through2-concurrent) instead, which is very similar to this otherwise.
#### original module
`miss.parallel` is provided by [`require('parallel-transform')`](https://npmjs.org/parallel-transform)
#### example
This example fetches the GET HTTP headers for a stream of input URLs 5 at a time in parallel.
```js
function getResponse (item, cb) {
var r = request(item.url)
r.on('error', function (err) {
cb(err)
})
r.on('response', function (re) {
cb(null, {url: item.url, date: new Date(), status: re.statusCode, headers: re.headers})
r.abort()
})
}
miss.pipe(
fs.createReadStream('./urls.txt'), // one url per line
split(),
miss.parallel(5, getResponse),
miss.through(function (row, enc, next) {
console.log(JSON.stringify(row))
next()
})
)
```
## see also
- [substack/stream-handbook](https://github.com/substack/stream-handbook)
- [nodejs.org/api/stream.html](https://nodejs.org/api/stream.html)
- [awesome-nodejs-streams](https://github.com/thejmazz/awesome-nodejs-streams)
## license
Licensed under the BSD 2-clause license.
+42
View File
@@ -0,0 +1,42 @@
'use strict';
const pTry = require('p-try');
module.exports = concurrency => {
if (concurrency < 1) {
throw new TypeError('Expected `concurrency` to be a number from 1 and up');
}
const queue = [];
let activeCount = 0;
const next = () => {
activeCount--;
if (queue.length > 0) {
queue.shift()();
}
};
return fn => new Promise((resolve, reject) => {
const run = () => {
activeCount++;
pTry(fn).then(
val => {
resolve(val);
next();
},
err => {
reject(err);
next();
}
);
};
if (activeCount < concurrency) {
run();
} else {
queue.push(run);
}
});
};
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+82
View File
@@ -0,0 +1,82 @@
{
"_from": "p-limit@^1.0.0",
"_id": "p-limit@1.3.0",
"_inBundle": false,
"_integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"_location": "/copy-webpack-plugin/p-limit",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "p-limit@^1.0.0",
"name": "p-limit",
"escapedName": "p-limit",
"rawSpec": "^1.0.0",
"saveSpec": null,
"fetchSpec": "^1.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin",
"/copy-webpack-plugin/p-locate"
],
"_resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"_shasum": "b86bd5f0c25690911c7590fcbfc2010d54b3ccb8",
"_spec": "p-limit@^1.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/p-limit/issues"
},
"bundleDependencies": false,
"dependencies": {
"p-try": "^1.0.0"
},
"deprecated": false,
"description": "Run multiple promise-returning & async functions with limited concurrency",
"devDependencies": {
"ava": "*",
"delay": "^2.0.0",
"in-range": "^1.0.0",
"random-int": "^1.0.0",
"time-span": "^2.0.0",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/p-limit#readme",
"keywords": [
"promise",
"limit",
"limited",
"concurrency",
"throttle",
"throat",
"rate",
"batch",
"ratelimit",
"task",
"queue",
"async",
"await",
"promises",
"bluebird"
],
"license": "MIT",
"name": "p-limit",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/p-limit.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "1.3.0"
}
+69
View File
@@ -0,0 +1,69 @@
# p-limit [![Build Status](https://travis-ci.org/sindresorhus/p-limit.svg?branch=master)](https://travis-ci.org/sindresorhus/p-limit)
> Run multiple promise-returning & async functions with limited concurrency
## Install
```
$ npm install p-limit
```
## Usage
```js
const pLimit = require('p-limit');
const limit = pLimit(1);
const input = [
limit(() => fetchSomething('foo')),
limit(() => fetchSomething('bar')),
limit(() => doSomething())
];
(async () => {
// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);
})();
```
## API
### pLimit(concurrency)
Returns a `limit` function.
#### concurrency
Type: `number`<br>
Minimum: `1`
Concurrency limit.
### limit(fn)
Returns the promise returned by calling `fn`.
#### fn
Type: `Function`
Promise-returning/async function.
## Related
- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control
- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
- [More…](https://github.com/sindresorhus/promise-fun)
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+31
View File
@@ -0,0 +1,31 @@
'use strict';
const pLimit = require('p-limit');
class EndError extends Error {
constructor(value) {
super();
this.value = value;
}
}
// the input can also be a promise, so we `Promise.all()` them both
const finder = el => Promise.all(el).then(val => val[1] === true && Promise.reject(new EndError(val[0])));
module.exports = (iterable, tester, opts) => {
opts = Object.assign({
concurrency: Infinity,
preserveOrder: true
}, opts);
const limit = pLimit(opts.concurrency);
// start all the promises concurrently with optional limit
const items = Array.from(iterable).map(el => [el, limit(() => Promise.resolve(el).then(tester))]);
// check the promises either serially or concurrently
const checkLimit = pLimit(opts.preserveOrder ? 1 : Infinity);
return Promise.all(items.map(el => checkLimit(() => finder(el))))
.then(() => {})
.catch(err => err instanceof EndError ? err.value : Promise.reject(err));
};
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+86
View File
@@ -0,0 +1,86 @@
{
"_from": "p-locate@^2.0.0",
"_id": "p-locate@2.0.0",
"_inBundle": false,
"_integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"_location": "/copy-webpack-plugin/p-locate",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "p-locate@^2.0.0",
"name": "p-locate",
"escapedName": "p-locate",
"rawSpec": "^2.0.0",
"saveSpec": null,
"fetchSpec": "^2.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/locate-path"
],
"_resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"_shasum": "20a0103b222a70c8fd39cc2e580680f3dde5ec43",
"_spec": "p-locate@^2.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\locate-path",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/p-locate/issues"
},
"bundleDependencies": false,
"dependencies": {
"p-limit": "^1.1.0"
},
"deprecated": false,
"description": "Get the first fulfilled promise that satisfies the provided testing function",
"devDependencies": {
"ava": "*",
"delay": "^1.3.1",
"in-range": "^1.0.0",
"time-span": "^1.0.0",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/p-locate#readme",
"keywords": [
"promise",
"locate",
"find",
"finder",
"search",
"searcher",
"test",
"array",
"collection",
"iterable",
"iterator",
"race",
"fulfilled",
"fastest",
"async",
"await",
"promises",
"bluebird"
],
"license": "MIT",
"name": "p-locate",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/p-locate.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "2.0.0",
"xo": {
"esnext": true
}
}
+86
View File
@@ -0,0 +1,86 @@
# p-locate [![Build Status](https://travis-ci.org/sindresorhus/p-locate.svg?branch=master)](https://travis-ci.org/sindresorhus/p-locate)
> Get the first fulfilled promise that satisfies the provided testing function
Think of it like an async version of [`Array#find`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
## Install
```
$ npm install --save p-locate
```
## Usage
Here we find the first file that exists on disk, in array order.
```js
const pathExists = require('path-exists');
const pLocate = require('p-locate');
const files = [
'unicorn.png',
'rainbow.png', // only this one actually exists on disk
'pony.png'
];
pLocate(files, file => pathExists(file)).then(foundPath => {
console.log(foundPath);
//=> 'rainbow'
});
```
*The above is just an example. Use [`locate-path`](https://github.com/sindresorhus/locate-path) if you need this.*
## API
### pLocate(input, tester, [options])
Returns a `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.
#### input
Type: `Iterable<Promise|any>`
#### tester(element)
Type: `Function`
Expected to return a `Promise<boolean>` or boolean.
#### options
Type: `Object`
##### concurrency
Type: `number`<br>
Default: `Infinity`<br>
Minimum: `1`
Number of concurrently pending promises returned by `tester`.
##### preserveOrder
Type: `boolean`<br>
Default: `true`
Preserve `input` order when searching.
Disable this to improve performance if you don't care about the order.
## Related
- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently
- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently
- [p-any](https://github.com/sindresorhus/p-any) - Wait for any promise to be fulfilled
- [More…](https://github.com/sindresorhus/promise-fun)
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+4
View File
@@ -0,0 +1,4 @@
'use strict';
module.exports = cb => new Promise(resolve => {
resolve(cb());
});
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+75
View File
@@ -0,0 +1,75 @@
{
"_from": "p-try@^1.0.0",
"_id": "p-try@1.0.0",
"_inBundle": false,
"_integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"_location": "/copy-webpack-plugin/p-try",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "p-try@^1.0.0",
"name": "p-try",
"escapedName": "p-try",
"rawSpec": "^1.0.0",
"saveSpec": null,
"fetchSpec": "^1.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/p-limit"
],
"_resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"_shasum": "cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3",
"_spec": "p-try@^1.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\p-limit",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/p-try/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "`Promise#try()` ponyfill - Starts a promise chain",
"devDependencies": {
"ava": "*",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/p-try#readme",
"keywords": [
"promise",
"try",
"resolve",
"function",
"catch",
"async",
"await",
"promises",
"settled",
"ponyfill",
"polyfill",
"shim",
"bluebird"
],
"license": "MIT",
"name": "p-try",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/p-try.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "1.0.0",
"xo": {
"esnext": true
}
}
+38
View File
@@ -0,0 +1,38 @@
# p-try [![Build Status](https://travis-ci.org/sindresorhus/p-try.svg?branch=master)](https://travis-ci.org/sindresorhus/p-try)
> [`Promise#try()`](https://github.com/ljharb/proposal-promise-try) [ponyfill](https://ponyfill.com) - Starts a promise chain
[How is it useful?](http://cryto.net/~joepie91/blog/2016/05/11/what-is-promise-try-and-why-does-it-matter/)
## Install
```
$ npm install --save p-try
```
## Usage
```js
const pTry = require('p-try');
pTry(() => {
return synchronousFunctionThatMightThrow();
}).then(value => {
console.log(value);
}).catch(error => {
console.error(error);
});
```
## Related
- [p-finally](https://github.com/sindresorhus/p-finally) - `Promise#finally()` ponyfill - Invoked when the promise is settled regardless of outcome
- [More…](https://github.com/sindresorhus/promise-fun)
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+84
View File
@@ -0,0 +1,84 @@
'use strict';
const processFn = (fn, opts) => function () {
const P = opts.promiseModule;
const args = new Array(arguments.length);
for (let i = 0; i < arguments.length; i++) {
args[i] = arguments[i];
}
return new P((resolve, reject) => {
if (opts.errorFirst) {
args.push(function (err, result) {
if (opts.multiArgs) {
const results = new Array(arguments.length - 1);
for (let i = 1; i < arguments.length; i++) {
results[i - 1] = arguments[i];
}
if (err) {
results.unshift(err);
reject(results);
} else {
resolve(results);
}
} else if (err) {
reject(err);
} else {
resolve(result);
}
});
} else {
args.push(function (result) {
if (opts.multiArgs) {
const results = new Array(arguments.length - 1);
for (let i = 0; i < arguments.length; i++) {
results[i] = arguments[i];
}
resolve(results);
} else {
resolve(result);
}
});
}
fn.apply(this, args);
});
};
module.exports = (obj, opts) => {
opts = Object.assign({
exclude: [/.+(Sync|Stream)$/],
errorFirst: true,
promiseModule: Promise
}, opts);
const filter = key => {
const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key);
return opts.include ? opts.include.some(match) : !opts.exclude.some(match);
};
let ret;
if (typeof obj === 'function') {
ret = function () {
if (opts.excludeMain) {
return obj.apply(this, arguments);
}
return processFn(obj, opts).apply(this, arguments);
};
} else {
ret = Object.create(Object.getPrototypeOf(obj));
}
for (const key in obj) { // eslint-disable-line guard-for-in
const x = obj[key];
ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x;
}
return ret;
};
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+84
View File
@@ -0,0 +1,84 @@
{
"_from": "pify@^3.0.0",
"_id": "pify@3.0.0",
"_inBundle": false,
"_integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"_location": "/copy-webpack-plugin/pify",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "pify@^3.0.0",
"name": "pify",
"escapedName": "pify",
"rawSpec": "^3.0.0",
"saveSpec": null,
"fetchSpec": "^3.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/globby",
"/copy-webpack-plugin/make-dir"
],
"_resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"_shasum": "e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176",
"_spec": "pify@^3.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\make-dir",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/pify/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Promisify a callback-style function",
"devDependencies": {
"ava": "*",
"pinkie-promise": "^2.0.0",
"v8-natives": "^1.0.0",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/pify#readme",
"keywords": [
"promise",
"promises",
"promisify",
"all",
"denodify",
"denodeify",
"callback",
"cb",
"node",
"then",
"thenify",
"convert",
"transform",
"wrap",
"wrapper",
"bind",
"to",
"async",
"await",
"es2015",
"bluebird"
],
"license": "MIT",
"name": "pify",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/pify.git"
},
"scripts": {
"optimization-test": "node --allow-natives-syntax optimization-test.js",
"test": "xo && ava && npm run optimization-test"
},
"version": "3.0.0"
}
+131
View File
@@ -0,0 +1,131 @@
# pify [![Build Status](https://travis-ci.org/sindresorhus/pify.svg?branch=master)](https://travis-ci.org/sindresorhus/pify)
> Promisify a callback-style function
## Install
```
$ npm install --save pify
```
## Usage
```js
const fs = require('fs');
const pify = require('pify');
// Promisify a single function
pify(fs.readFile)('package.json', 'utf8').then(data => {
console.log(JSON.parse(data).name);
//=> 'pify'
});
// Promisify all methods in a module
pify(fs).readFile('package.json', 'utf8').then(data => {
console.log(JSON.parse(data).name);
//=> 'pify'
});
```
## API
### pify(input, [options])
Returns a `Promise` wrapped version of the supplied function or module.
#### input
Type: `Function` `Object`
Callback-style function or module whose methods you want to promisify.
#### options
##### multiArgs
Type: `boolean`<br>
Default: `false`
By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. This also applies to rejections, where it returns an array of all the callback arguments, including the error.
```js
const request = require('request');
const pify = require('pify');
pify(request, {multiArgs: true})('https://sindresorhus.com').then(result => {
const [httpResponse, body] = result;
});
```
##### include
Type: `string[]` `RegExp[]`
Methods in a module to promisify. Remaining methods will be left untouched.
##### exclude
Type: `string[]` `RegExp[]`<br>
Default: `[/.+(Sync|Stream)$/]`
Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default.
##### excludeMain
Type: `boolean`<br>
Default: `false`
If given module is a function itself, it will be promisified. Turn this option on if you want to promisify only methods of the module.
```js
const pify = require('pify');
function fn() {
return true;
}
fn.method = (data, callback) => {
setImmediate(() => {
callback(null, data);
});
};
// Promisify methods but not `fn()`
const promiseFn = pify(fn, {excludeMain: true});
if (promiseFn()) {
promiseFn.method('hi').then(data => {
console.log(data);
});
}
```
##### errorFirst
Type: `boolean`<br>
Default: `true`
Whether the callback has an error as the first argument. You'll want to set this to `false` if you're dealing with an API that doesn't have an error as the first argument, like `fs.exists()`, some browser APIs, Chrome Extension APIs, etc.
##### promiseModule
Type: `Function`
Custom promise module to use instead of the native one.
Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill.
## Related
- [p-event](https://github.com/sindresorhus/p-event) - Promisify an event by waiting for it to be emitted
- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently
- [More…](https://github.com/sindresorhus/promise-fun)
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+10
View File
@@ -0,0 +1,10 @@
'use strict';
const path = require('path');
const findUp = require('find-up');
module.exports = cwd => findUp('package.json', {cwd}).then(fp => fp ? path.dirname(fp) : null);
module.exports.sync = cwd => {
const fp = findUp.sync('package.json', {cwd});
return fp ? path.dirname(fp) : null;
};
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+85
View File
@@ -0,0 +1,85 @@
{
"_from": "pkg-dir@^2.0.0",
"_id": "pkg-dir@2.0.0",
"_inBundle": false,
"_integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
"_location": "/copy-webpack-plugin/pkg-dir",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "pkg-dir@^2.0.0",
"name": "pkg-dir",
"escapedName": "pkg-dir",
"rawSpec": "^2.0.0",
"saveSpec": null,
"fetchSpec": "^2.0.0"
},
"_requiredBy": [
"/copy-webpack-plugin/find-cache-dir"
],
"_resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
"_shasum": "f6d5d1109e19d63edf428e0bd57e12777615334b",
"_spec": "pkg-dir@^2.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\find-cache-dir",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/pkg-dir/issues"
},
"bundleDependencies": false,
"dependencies": {
"find-up": "^2.1.0"
},
"deprecated": false,
"description": "Find the root directory of a Node.js project or npm package",
"devDependencies": {
"ava": "*",
"xo": "*"
},
"engines": {
"node": ">=4"
},
"files": [
"index.js"
],
"homepage": "https://github.com/sindresorhus/pkg-dir#readme",
"keywords": [
"package",
"json",
"root",
"npm",
"entry",
"find",
"up",
"find-up",
"findup",
"look-up",
"look",
"file",
"search",
"match",
"resolve",
"parent",
"parents",
"folder",
"directory",
"dir",
"walk",
"walking",
"path"
],
"license": "MIT",
"name": "pkg-dir",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/pkg-dir.git"
},
"scripts": {
"test": "xo && ava"
},
"version": "2.0.0"
}
+64
View File
@@ -0,0 +1,64 @@
# pkg-dir [![Build Status](https://travis-ci.org/sindresorhus/pkg-dir.svg?branch=master)](https://travis-ci.org/sindresorhus/pkg-dir)
> Find the root directory of a Node.js project or npm package
## Install
```
$ npm install --save pkg-dir
```
## Usage
```
/
└── Users
└── sindresorhus
└── foo
├── package.json
└── bar
├── baz
└── example.js
```
```js
// example.js
const pkgDir = require('pkg-dir');
pkgDir(__dirname).then(rootDir => {
console.log(rootDir);
//=> '/Users/sindresorhus/foo'
});
```
## API
### pkgDir([cwd])
Returns a `Promise` for either the project root path or `null` if it couldn't be found.
### pkgDir.sync([cwd])
Returns the project root path or `null`.
#### cwd
Type: `string`<br>
Default: `process.cwd()`
Directory to start from.
## Related
- [pkg-dir-cli](https://github.com/sindresorhus/pkg-dir-cli) - CLI for this module
- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
- [find-up](https://github.com/sindresorhus/find-up) - Find a file by walking up parent directories
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)
+5
View File
@@ -0,0 +1,5 @@
language: node_js
node_js:
- "0.10"
script: "npm test"
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Mathias Buus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+56
View File
@@ -0,0 +1,56 @@
# pump
pump is a small node module that pipes streams together and destroys all of them if one of them closes.
```
npm install pump
```
[![build status](http://img.shields.io/travis/mafintosh/pump.svg?style=flat)](http://travis-ci.org/mafintosh/pump)
## What problem does it solve?
When using standard `source.pipe(dest)` source will _not_ be destroyed if dest emits close or an error.
You are also not able to provide a callback to tell when then pipe has finished.
pump does these two things for you
## Usage
Simply pass the streams you want to pipe together to pump and add an optional callback
``` js
var pump = require('pump')
var fs = require('fs')
var source = fs.createReadStream('/dev/random')
var dest = fs.createWriteStream('/dev/null')
pump(source, dest, function(err) {
console.log('pipe finished', err)
})
setTimeout(function() {
dest.destroy() // when dest is closed pump will destroy source
}, 1000)
```
You can use pump to pipe more than two streams together as well
``` js
var transform = someTransformStream()
pump(source, transform, anotherTransform, dest, function(err) {
console.log('pipe finished', err)
})
```
If `source`, `transform`, `anotherTransform` or `dest` closes all of them will be destroyed.
## License
MIT
## Related
`pump` is part of the [mississippi stream utility collection](https://github.com/maxogden/mississippi) which includes more useful stream modules similar to this one.
+82
View File
@@ -0,0 +1,82 @@
var once = require('once')
var eos = require('end-of-stream')
var fs = require('fs') // we only need fs to get the ReadStream and WriteStream prototypes
var noop = function () {}
var ancient = /^v?\.0/.test(process.version)
var isFn = function (fn) {
return typeof fn === 'function'
}
var isFS = function (stream) {
if (!ancient) return false // newer node version do not need to care about fs is a special way
if (!fs) return false // browser
return (stream instanceof (fs.ReadStream || noop) || stream instanceof (fs.WriteStream || noop)) && isFn(stream.close)
}
var isRequest = function (stream) {
return stream.setHeader && isFn(stream.abort)
}
var destroyer = function (stream, reading, writing, callback) {
callback = once(callback)
var closed = false
stream.on('close', function () {
closed = true
})
eos(stream, {readable: reading, writable: writing}, function (err) {
if (err) return callback(err)
closed = true
callback()
})
var destroyed = false
return function (err) {
if (closed) return
if (destroyed) return
destroyed = true
if (isFS(stream)) return stream.close(noop) // use close for fs streams to avoid fd leaks
if (isRequest(stream)) return stream.abort() // request.destroy just do .end - .abort is what we want
if (isFn(stream.destroy)) return stream.destroy()
callback(err || new Error('stream was destroyed'))
}
}
var call = function (fn) {
fn()
}
var pipe = function (from, to) {
return from.pipe(to)
}
var pump = function () {
var streams = Array.prototype.slice.call(arguments)
var callback = isFn(streams[streams.length - 1] || noop) && streams.pop() || noop
if (Array.isArray(streams[0])) streams = streams[0]
if (streams.length < 2) throw new Error('pump requires two streams per minimum')
var error
var destroys = streams.map(function (stream, i) {
var reading = i < streams.length - 1
var writing = i > 0
return destroyer(stream, reading, writing, function (err) {
if (!error) error = err
if (err) destroys.forEach(call)
if (reading) return
destroys.forEach(call)
callback(error)
})
})
streams.reduce(pipe)
}
module.exports = pump
+59
View File
@@ -0,0 +1,59 @@
{
"_from": "pump@^2.0.1",
"_id": "pump@2.0.1",
"_inBundle": false,
"_integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
"_location": "/copy-webpack-plugin/pump",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "pump@^2.0.1",
"name": "pump",
"escapedName": "pump",
"rawSpec": "^2.0.1",
"saveSpec": null,
"fetchSpec": "^2.0.1"
},
"_requiredBy": [
"/copy-webpack-plugin/mississippi"
],
"_resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
"_shasum": "12399add6e4cf7526d973cbc8b5ce2e2908b3909",
"_spec": "pump@^2.0.1",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\copy-webpack-plugin\\node_modules\\mississippi",
"author": {
"name": "Mathias Buus Madsen",
"email": "mathiasbuus@gmail.com"
},
"browser": {
"fs": false
},
"bugs": {
"url": "https://github.com/mafintosh/pump/issues"
},
"bundleDependencies": false,
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
},
"deprecated": false,
"description": "pipe streams together and close all of them if one of them closes",
"homepage": "https://github.com/mafintosh/pump#readme",
"keywords": [
"streams",
"pipe",
"destroy",
"callback"
],
"license": "MIT",
"name": "pump",
"repository": {
"type": "git",
"url": "git://github.com/mafintosh/pump.git"
},
"scripts": {
"test": "node test-browser.js && node test-node.js"
},
"version": "2.0.1"
}
+62
View File
@@ -0,0 +1,62 @@
var stream = require('stream')
var pump = require('./index')
var rs = new stream.Readable()
var ws = new stream.Writable()
rs._read = function (size) {
this.push(Buffer(size).fill('abc'))
}
ws._write = function (chunk, encoding, cb) {
setTimeout(function () {
cb()
}, 100)
}
var toHex = function () {
var reverse = new (require('stream').Transform)()
reverse._transform = function (chunk, enc, callback) {
reverse.push(chunk.toString('hex'))
callback()
}
return reverse
}
var wsClosed = false
var rsClosed = false
var callbackCalled = false
var check = function () {
if (wsClosed && rsClosed && callbackCalled) {
console.log('test-browser.js passes')
clearTimeout(timeout)
}
}
ws.on('finish', function () {
wsClosed = true
check()
})
rs.on('end', function () {
rsClosed = true
check()
})
pump(rs, toHex(), toHex(), toHex(), ws, function () {
callbackCalled = true
check()
})
setTimeout(function () {
rs.push(null)
rs.emit('close')
}, 1000)
var timeout = setTimeout(function () {
check()
throw new Error('timeout')
}, 5000)
+53
View File
@@ -0,0 +1,53 @@
var pump = require('./index')
var rs = require('fs').createReadStream('/dev/random')
var ws = require('fs').createWriteStream('/dev/null')
var toHex = function () {
var reverse = new (require('stream').Transform)()
reverse._transform = function (chunk, enc, callback) {
reverse.push(chunk.toString('hex'))
callback()
}
return reverse
}
var wsClosed = false
var rsClosed = false
var callbackCalled = false
var check = function () {
if (wsClosed && rsClosed && callbackCalled) {
console.log('test-node.js passes')
clearTimeout(timeout)
}
}
ws.on('close', function () {
wsClosed = true
check()
})
rs.on('close', function () {
rsClosed = true
check()
})
var res = pump(rs, toHex(), toHex(), toHex(), ws, function () {
callbackCalled = true
check()
})
if (res) {
process.exit(1)
}
setTimeout(function () {
rs.destroy()
}, 1000)
var timeout = setTimeout(function () {
throw new Error('timeout')
}, 5000)
+11
View File
@@ -0,0 +1,11 @@
'use strict';
module.exports = function (str) {
var isExtendedLengthPath = /^\\\\\?\\/.test(str);
var hasNonAscii = /[^\x00-\x80]+/.test(str);
if (isExtendedLengthPath || hasNonAscii) {
return str;
}
return str.replace(/\\/g, '/');
};

Some files were not shown because too many files have changed in this diff Show More