Skip to content

Commit 0c6099f

Browse files
committed
feat: 1st implementation
1 parent fd68844 commit 0c6099f

35 files changed

+2174
-9
lines changed

.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
coverage

.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "eslint-config-egg"
3+
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
node_modules
2+
npm-debug.log
3+
coverage

.travis.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
sudo: false
2+
language: node_js
3+
node_js:
4+
- '4'
5+
- '6'
6+
- '7'
7+
install:
8+
- npm i npm && npm i
9+
script:
10+
- npm run ci
11+
after_script:
12+
- npm i codecov && codecov

README.md

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
# compressible
2+
3+
[![NPM version][npm-image]][npm-url]
4+
[![build status][travis-image]][travis-url]
5+
[![Test coverage][codecov-image]][codecov-url]
6+
[![David deps][david-image]][david-url]
7+
[![Known Vulnerabilities][snyk-image]][snyk-url]
8+
[![npm download][download-image]][download-url]
9+
10+
[npm-image]: https://img.shields.io/npm/v/compressible.svg?style=flat-square
11+
[npm-url]: https://npmjs.org/package/compressible
12+
[travis-image]: https://img.shields.io/travis/node-modules/compressible.svg?style=flat-square
13+
[travis-url]: https://travis-ci.org/node-modules/compressible
14+
[codecov-image]: https://codecov.io/gh/node-modules/compressible/branch/master/graph/badge.svg
15+
[codecov-url]: https://codecov.io/gh/node-modules/compressible
16+
[david-image]: https://img.shields.io/david/node-modules/compressible.svg?style=flat-square
17+
[david-url]: https://david-dm.org/node-modules/compressible
18+
[snyk-image]: https://snyk.io/test/npm/compressible/badge.svg?style=flat-square
19+
[snyk-url]: https://snyk.io/test/npm/compressible
20+
[download-image]: https://img.shields.io/npm/dm/compressible.svg?style=flat-square
21+
[download-url]: https://npmjs.org/package/compressible
22+
23+
The missing compress and uncompress lib for node.
24+
25+
__Currently uncompressing has not been supported yet.__
26+
27+
Currently supported:
28+
29+
- tar
30+
- gzip
31+
- tgz
32+
- zip
33+
34+
## Install
35+
36+
```bash
37+
npm install compressible
38+
```
39+
40+
## Usage
41+
42+
### Compress a single file
43+
44+
Use gzip as an example, tar, tgz and zip is same as gzip.
45+
46+
__promise style__
47+
48+
```js
49+
const compressible = require('compressible');
50+
51+
// compress a file
52+
compressible.gzip.compressFile('file/path/to/compress', 'path/to/destination.gz')
53+
.then(compressDone)
54+
.catch(handleError);
55+
56+
// compress a file buffer
57+
compressible.gzip.compressFile(buffer, 'path/to/destination.gz')
58+
.then(compressDone)
59+
.catch(handleError);
60+
61+
// compress a stream
62+
compressible.gzip.compressFile(stream, 'path/to/destination.gz')
63+
.then(compressDone)
64+
.catch(handleError);
65+
```
66+
67+
__stream style__
68+
69+
```js
70+
const compressible = require('compressible');
71+
72+
new compressible.gzip.FileStream({ source: 'file/path/to/compress' })
73+
.on('error', handleError)
74+
.pipe(fs.createWriteStream('path/to/destination.gz'))
75+
.on('error', handleError);
76+
77+
// It's a transform stream, so you can pipe to it
78+
fs.createReadStream('file/path/to/compress')
79+
.on('error', handleError)
80+
.pipe(new compressible.gzip.FileStream())
81+
.on('error', handleError)
82+
.pipe(fs.createWriteStream('path/to/destination.gz'))
83+
.on('error', handleError);
84+
85+
// You should take care of stream errors in caution, use multipipe to handle error in one place
86+
const pipe = require('multipipe';)
87+
const sourceStream = fs.createReadStream('file/path/to/compress')
88+
const gzipStream = new compressible.gzip.FileStream();
89+
const destStream = fs.createWriteStream('path/to/destination.gz');
90+
pipe(sourceStream, gzipStream, destStream, err => handleError);
91+
```
92+
93+
94+
### Compress a dir
95+
96+
Use tar as an example, tgz and zip is same as gzip.
97+
98+
__Gzip only support compressing a single file. if you want to compress a dir with gzip, then you may need tgz instead.__
99+
100+
__promise style__
101+
102+
```js
103+
const compressible = require('compressible');
104+
compressible.tar.compressDir('dir/path/to/compress', 'path/to/destination.tar')
105+
.then(compressDone)
106+
.catch(handleError);
107+
```
108+
109+
__stream style__
110+
111+
```js
112+
const compressible = require('compressible');
113+
114+
const tarStream = new compressible.tar.Stream();
115+
tarStream.addEntry('dir/path/to/compress');
116+
117+
tarStream
118+
.on('error', handleError)
119+
.pipe(fs.createWriteStream('path/to/destination.tar'))
120+
.on('error', handleError);
121+
122+
// You should take care of stream errors in caution, use multipipe to handle error in one place
123+
const tarStream = new compressible.tar.Stream();
124+
tarStream.addEntry('dir/path/to/compress');
125+
const destStream = fs.createWriteStream('path/to/destination.tar');
126+
pipe(tarStream, destStream, handleError);
127+
```
128+
129+
Stream is very powerful, you can compress multiple entries in it;
130+
131+
```js
132+
const tarStream = new compressible.tar.Stream();
133+
// dir
134+
tarStream.addEntry('dir/path/to/compress');
135+
136+
// file
137+
tarStream.addEntry('file/path/to/compress');
138+
139+
// buffer
140+
tarStream.addEntry(buffer);
141+
142+
// stream
143+
tarStream.addEntry(stream);
144+
145+
const destStream = fs.createWriteStream('path/to/destination.tar');
146+
pipe(tarStream, destStream, handleError);
147+
```
148+
149+
## API
150+
151+
### compressFile
152+
153+
Use this API to compress a single file. This is a convenient method, which wraps FileStream API below, but you can handle error in one place.
154+
155+
- gzip.compressFile(source, dest, opts)
156+
- tar.compressFile(source, dest, opts)
157+
- tgz.compressFile(source, dest, opts)
158+
- zip.compressFile(source, dest, opts)
159+
160+
Params
161+
162+
- source {String|Buffer|Stream} - source to be compressed, could be a file path, buffer, or a readable stream
163+
- dest {String|Stream} - compressing destination, could be a file path(eg. `/path/to/xx.tgz`), or a writable stream.
164+
- opts {Object} - usually you don't need it
165+
166+
Returns a promise object.
167+
168+
### compressDir
169+
170+
Use this API to compress a dir. This is a convenient method, which wraps Stream API below, but you can handle error in one place.
171+
172+
__Note: gzip do not have a compressDir method, you may need tgz instead.__
173+
174+
- tar.compressDir(dir, dest, opts)
175+
- tgz.compressDir(dir, dest, opts)
176+
- zip.compressDir(dir, dest, opts)
177+
178+
Params
179+
180+
- dir {String|Buffer|Stream} - dir path to be compressed
181+
- dest {String|Stream} - compressing destination, could be a file path(eg. `/path/to/xx.tgz`), or a writable stream.
182+
- opts {Object} - usually you don't need it
183+
184+
### FileStream
185+
186+
The transform stream to compress a single file.
187+
188+
__Note: If you are not very familiar with streams, just use compressFile() API, error can be handled in one place.__
189+
190+
- new gzip.FileStream(opts)
191+
- new tar.FileStream(opts)
192+
- new tgz.FileStream(opts)
193+
- new zip.FileStream(opts)
194+
195+
Common params:
196+
197+
- opts.source {String|Buffer|Stream} - source to be compressed, could be a file path, buffer, or a readable stream.
198+
199+
Gzip params:
200+
201+
- opts.zlib - {Object} gzip.FileStream uses zlib to compress, pass this param to control the behavior of zlib.
202+
203+
Tar params:
204+
205+
- opts.relativePath {String} - Adds a file from source into the compressed result file as opts.relativePath. Uncompression programs would extract the file from the compressed file as relativePath. If opts.source is a file path, opts.relativePath is optional, otherwise it's required.
206+
- opts.size {Number} - Tar compression requires the size of file in advance. When opts.source is a stream, the size of it cannot be calculated unless load all content of the stream into memory(the default behavior, but loading all data into memory could be a very bad idea). Pass opts.size to avoid loading all data into memory, or a warning will be shown.
207+
- opts.suppressSizeWarning {Boolean} - Pass true to suppress the size warning mentioned.
208+
209+
Tgz params:
210+
211+
tgz.FileStream is a combination of tar.FileStream and gzip.FileStream, so the params are the combination of params of tar and gzip.
212+
213+
Zip params:
214+
215+
- opts.relativePath {String} - Adds a file from source into the compressed result file as opts.relativePath. Uncompression programs would extract the file from the compressed file as relativePath. If opts.source is a file path, opts.relativePath is optional, otherwise it's required.
216+
- opts.yazl {Object} - zip.FileStream compression uses [yazl](https://github.com/thejoshwolfe/yazl), pass this param to control the behavior of yazl.
217+
218+
### Stream
219+
220+
The readable stream to compress anything as you need.
221+
222+
__Note: If you are not very familiar with streams, just use compressFile() and compressDir() API, error can be handled in one place.__
223+
224+
__Gzip only support compressing a single file. So gzip.Stream is not available.__
225+
226+
__Constructor__
227+
228+
- new tar.Stream()
229+
- new tgz.Stream()
230+
- new zip.Stream()
231+
232+
No options in all constructors.
233+
234+
__Instance methods__
235+
236+
- addEntry(entry, opts)
237+
238+
Params
239+
240+
- entry {String|Buffer|Stream} - entry to compress, cound be a file path, a dir path, a buffer, or a stream.
241+
- opts.relativePath {String} - uncompression programs would extract the file from the compressed file as opts.relativePath. If entry is a file path or a dir path, opts.relativePath is optional, otherwise it's required.
242+
- opts.ignoreBase {Boolean} - when entry is a dir path, and opts.ignoreBase is set to true, the compression will contain files relative to the path passed, and not with the path included.
243+
244+
245+
246+

index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use strict';
2+
3+
exports.zip = require('./lib/zip');
4+
exports.gzip = require('./lib/gzip');
5+
exports.tar = require('./lib/tar');
6+
exports.tgz = require('./lib/tgz');

lib/base_stream.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
'use strict';
2+
3+
const stream = require('stream');
4+
5+
class BaseStream extends stream.Readable {
6+
addEntry(/* entry, opts */) {
7+
throw new Error('.addEntry not implemented in sub class!');
8+
}
9+
10+
_read() {}
11+
}
12+
13+
module.exports = BaseStream;
14+

lib/gzip/file_stream.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const zlib = require('zlib');
5+
const utils = require('../utils');
6+
const streamifier = require('streamifier');
7+
8+
class GzipFileStream extends zlib.Gzip {
9+
constructor(opts) {
10+
opts = opts || {};
11+
super(opts.zlib);
12+
13+
const sourceType = utils.sourceType(opts.source);
14+
15+
if (sourceType === 'file') {
16+
const stream = fs.createReadStream(opts.source, opts.fs);
17+
stream.on('error', err => this.emit('error', err));
18+
stream.pipe(this);
19+
return;
20+
}
21+
22+
if (sourceType === 'buffer') {
23+
const stream = streamifier.createReadStream(opts.source, opts.streamifier);
24+
stream.on('error', err => this.emit('error', err));
25+
stream.pipe(this);
26+
return;
27+
}
28+
29+
if (sourceType === 'stream') {
30+
opts.source.on('error', err => this.emit('error', err));
31+
opts.source.pipe(this);
32+
}
33+
34+
// else undefined: do nothing
35+
}
36+
}
37+
38+
module.exports = GzipFileStream;

lib/gzip/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
'use strict';
2+
3+
const utils = require('../utils');
4+
const GzipFileStream = require('./file_stream');
5+
6+
exports.FileStream = GzipFileStream;
7+
exports.compressFile = utils.makeCompressFileFunc(GzipFileStream);

0 commit comments

Comments
 (0)