Comparing version 1.0.7 to 2.0.0
@@ -9,8 +9,20 @@ import { Options } from './types/Options'; | ||
*/ | ||
create(path: string, options: Options): Promise<string>; | ||
fromPath(path: string, options: Options): Promise<string>; | ||
/** | ||
* Add multiple files to a single ZIP file | ||
*/ | ||
createBulk(paths: string[], options: Options): Promise<string>; | ||
fromPaths(paths: string[], options: Options): Promise<string>; | ||
/** | ||
* Create a ZIP containing all files within specified directory | ||
*/ | ||
fromDirectory(path: string, options: Options): Promise<string>; | ||
/** | ||
* Create a ZIP containing files matching the specified pattern at the specified path | ||
*/ | ||
fromPattern(path: string, pattern: string, options: Options): Promise<string>; | ||
/** | ||
* Returns the configured archiver | ||
*/ | ||
private getArchiver; | ||
/** | ||
* Returns the output path configured with specified options or defaults | ||
@@ -17,0 +29,0 @@ */ |
@@ -16,3 +16,3 @@ "use strict"; | ||
*/ | ||
create(path, options) { | ||
fromPath(path, options) { | ||
const fileParts = new FileParts_1.FileParts(path); | ||
@@ -25,5 +25,3 @@ const archiveData = { | ||
const createZip = (sourceBuffer) => { | ||
const writeStream = fs.createWriteStream(outputLocation); | ||
const archive = ArchiverFactory_1.ArchiverFactory.getArchiver(options); | ||
archive.pipe(writeStream); | ||
const archive = this.getArchiver(options, outputLocation); | ||
archive.append(sourceBuffer, archiveData); | ||
@@ -45,9 +43,7 @@ return archive.finalize(); | ||
*/ | ||
createBulk(paths, options) { | ||
fromPaths(paths, options) { | ||
const outputLocation = this.getOutputPath(options); | ||
const mapToFileParts = () => paths.map((path) => new FileParts_1.FileParts(path)); | ||
const appendToZIP = (fileParts) => { | ||
const writeStream = fs.createWriteStream(outputLocation); | ||
const archive = ArchiverFactory_1.ArchiverFactory.getArchiver(options); | ||
archive.pipe(writeStream); | ||
const archive = this.getArchiver(options, outputLocation); | ||
fileParts.forEach((filePart) => { | ||
@@ -73,2 +69,52 @@ const sourceBuffer = fs.readFileSync(filePart.getPath()); | ||
/** | ||
* Create a ZIP containing all files within specified directory | ||
*/ | ||
fromDirectory(path, options) { | ||
const outputLocation = this.getOutputPath(options); | ||
const createZip = () => { | ||
const archive = this.getArchiver(options, outputLocation); | ||
archive.directory(path, false); | ||
return archive.finalize(); | ||
}; | ||
const mapSuccess = () => outputLocation; | ||
const tapError = (error) => { | ||
throw new ZipsterError_1.ZipsterError(error.message); | ||
}; | ||
return Promise.resolve() | ||
.then(createZip) | ||
.then(mapSuccess) | ||
.catch(tapError); | ||
} | ||
/** | ||
* Create a ZIP containing files matching the specified pattern at the specified path | ||
*/ | ||
fromPattern(path, pattern, options) { | ||
const outputLocation = this.getOutputPath(options); | ||
const globOptions = { | ||
cwd: path | ||
}; | ||
const createZip = () => { | ||
const archive = this.getArchiver(options, outputLocation); | ||
archive.glob(pattern, globOptions); | ||
return archive.finalize(); | ||
}; | ||
const mapSuccess = () => outputLocation; | ||
const tapError = (error) => { | ||
throw new ZipsterError_1.ZipsterError(error.message); | ||
}; | ||
return Promise.resolve() | ||
.then(createZip) | ||
.then(mapSuccess) | ||
.catch(tapError); | ||
} | ||
/** | ||
* Returns the configured archiver | ||
*/ | ||
getArchiver(options, outputLocation) { | ||
const writeStream = fs.createWriteStream(outputLocation); | ||
const archive = ArchiverFactory_1.ArchiverFactory.getArchiver(options); | ||
archive.pipe(writeStream); | ||
return archive; | ||
} | ||
/** | ||
* Returns the output path configured with specified options or defaults | ||
@@ -75,0 +121,0 @@ */ |
{ | ||
"name": "zipster", | ||
"version": "1.0.7", | ||
"version": "2.0.0", | ||
"description": "TypeScript library built for Node backends to create ZIP files with password protection", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -23,5 +23,7 @@ # Zipster | ||
- [Usage](#usage) | ||
- [Create a ZIP with a single file](#createpath-string-options-options) | ||
- [Create a ZIP with multiple files](#createbulkpaths-string-options-options) | ||
- [Create a ZIP with a single file](#frompathpath-string-options-options) | ||
- [Create a ZIP with multiple files](#frompathspaths-string-options-options) | ||
- [Create a ZIP from a directory](#fromdirectorypath-string-options-options) | ||
- [Options](#options) | ||
- [Password Example](#password-example) | ||
- [Tests](#running-tests) | ||
@@ -55,3 +57,3 @@ - [Issues](#issues) | ||
#### .create(path: string, options: Options) | ||
#### .fromPath(path: string, options: Options) | ||
@@ -67,7 +69,7 @@ Create ZIP file containing a single file | ||
const zipster = new Zipster() | ||
zipster.create(path, options) | ||
zipster.fromPath(path, options) | ||
.then((outputPath: string) => console.log({ outputPath }, 'Successfully created ZIP')) | ||
``` | ||
#### .createBulk(paths: string[], options: Options) | ||
#### .fromPaths(paths: string[], options: Options) | ||
@@ -77,3 +79,3 @@ Create ZIP file containing multiple files | ||
```typescript | ||
const path = [ | ||
const paths = [ | ||
'/some/path/to/my/file.txt', | ||
@@ -87,6 +89,38 @@ '/some/path/to/my/file.csv' | ||
const zipster = new Zipster() | ||
zipster.createBulk(paths, options) | ||
zipster.fromPaths(paths, options) | ||
.then((outputPath: string) => console.log({ outputPath }, 'Successfully created ZIP')) | ||
``` | ||
#### .fromDirectory(path: string, options: Options) | ||
Creates a ZIP file containing all the sub-directories at a given path, retaining the folder structure of the | ||
sub-directories | ||
```typescript | ||
const path = '/some/path/to/my/directory' | ||
const options: Options = { | ||
format: Formats.ZIP | ||
} | ||
const zipster = new Zipster() | ||
zipster.fromDirectory(path, options) | ||
.then((outputPath: string) => console.log({ outputPath }, 'Successfully created ZIP')) | ||
``` | ||
#### .fromPattern(path: string, pattern: string, options: Options) | ||
Creates a ZIP file containing all the files matching the given pattern at the given path | ||
```typescript | ||
const path = '/some/path/to/my/directory' | ||
const pattern = 'foo*.txt' | ||
const options: Options = { | ||
format: Formats.ZIP | ||
} | ||
const zipster = new Zipster() | ||
zipster.fromPattern(path, pattern, options) | ||
.then((outputPath: string) => console.log({ outputPath }, 'Successfully created ZIP')) | ||
``` | ||
#### Options | ||
@@ -101,2 +135,18 @@ | ||
#### Password Example | ||
Create a password-protected ZIP file | ||
```typescript | ||
const path = '/some/path/to/my/file.txt' | ||
const options: Options = { | ||
format: Formats.ZIP_ENCRYPTABLE, | ||
password: 'super-sensitive-password' | ||
} | ||
const zipster = new Zipster() | ||
zipster.fromPath(path, options) | ||
.then((outputPath: string) => console.log({ outputPath }, 'Successfully created ZIP')) | ||
``` | ||
## Tests | ||
@@ -103,0 +153,0 @@ |
import { SinonSandbox } from 'sinon' | ||
const mockArchiver = (sandbox: SinonSandbox) => ({ | ||
glob: sandbox.stub(), | ||
pipe: sandbox.stub(), | ||
append: sandbox.stub(), | ||
finalize: sandbox.stub() | ||
finalize: sandbox.stub(), | ||
directory: sandbox.stub() | ||
}) | ||
export { mockArchiver } |
@@ -6,2 +6,3 @@ import * as fs from 'fs' | ||
import { IOptions } from 'glob' | ||
import { createSandbox } from 'sinon' | ||
@@ -15,4 +16,5 @@ | ||
const sandbox = createSandbox() | ||
const file = '/some/path/to/file.txt' | ||
const defaultFileName = 'xxxx-xxxx-xxxx-xxxx' | ||
const directory = '/some/path/to/file.txt' | ||
const expectedOutputFile = `/some/path/to/${defaultFileName}.zip` | ||
const options: Options = { | ||
@@ -32,3 +34,3 @@ format: Formats.ZIP | ||
let zipper: Zipster | ||
let zipster: Zipster | ||
@@ -46,3 +48,3 @@ beforeEach(() => { | ||
zipper = new Zipster() | ||
zipster = new Zipster() | ||
}) | ||
@@ -52,5 +54,3 @@ | ||
describe('#create', () => { | ||
const expectedDirectory = `/some/path/to/${defaultFileName}.zip` | ||
describe('#fromPath', () => { | ||
beforeEach(() => { | ||
@@ -83,4 +83,4 @@ tmpdir.onFirstCall() | ||
return zipper.create(directory, options) | ||
.should.become(expectedDirectory) | ||
return zipster.fromPath(file, options) | ||
.should.become(expectedOutputFile) | ||
}) | ||
@@ -96,8 +96,8 @@ | ||
return zipper.create(directory, options) | ||
.should.become(expectedDirectory) | ||
return zipster.fromPath(file, options) | ||
.should.become(expectedOutputFile) | ||
.then(() => { | ||
tmpdir.should.have.callCount(1) | ||
readFileSync.should.have.been.calledOnceWithExactly(directory) | ||
createWriteStream.should.have.been.calledOnceWithExactly(expectedDirectory) | ||
readFileSync.should.have.been.calledOnceWithExactly(file) | ||
createWriteStream.should.have.been.calledOnceWithExactly(expectedOutputFile) | ||
getArchiver.should.have.been.calledOnceWithExactly(options) | ||
@@ -117,3 +117,3 @@ archiver.pipe.should.have.been.calledOnceWithExactly(stream) | ||
return zipper.create(directory, options) | ||
return zipster.fromPath(file, options) | ||
.should.be.rejectedWith(ZipsterError, error.message) | ||
@@ -123,6 +123,5 @@ }) | ||
describe('#createBulk', () => { | ||
const expectedDirectory = `/some/path/to/${defaultFileName}.zip` | ||
describe('#fromPaths', () => { | ||
const directories = [ | ||
directory, | ||
file, | ||
'/some/path/to/other.csv' | ||
@@ -154,4 +153,4 @@ ] | ||
return zipper.createBulk(directories, options) | ||
.should.become(expectedDirectory) | ||
return zipster.fromPaths(directories, options) | ||
.should.become(expectedOutputFile) | ||
}) | ||
@@ -171,3 +170,3 @@ | ||
return zipper.createBulk(directories, options) | ||
return zipster.fromPaths(directories, options) | ||
.should.become(expectedDirectory) | ||
@@ -184,4 +183,4 @@ }) | ||
return zipper.createBulk(directories, options) | ||
.should.become(expectedDirectory) | ||
return zipster.fromPaths(directories, options) | ||
.should.become(expectedOutputFile) | ||
}) | ||
@@ -192,3 +191,3 @@ | ||
return zipper.createBulk(directories, options) | ||
return zipster.fromPaths(directories, options) | ||
.should.be.fulfilled | ||
@@ -200,3 +199,3 @@ .then(() => { | ||
readFileSync.should.have.been.calledWithExactly(directories[1]) | ||
createWriteStream.should.have.been.calledOnceWithExactly(expectedDirectory) | ||
createWriteStream.should.have.been.calledOnceWithExactly(expectedOutputFile) | ||
getArchiver.should.have.been.calledOnceWithExactly(options) | ||
@@ -216,6 +215,151 @@ archiver.pipe.should.have.callCount(1) | ||
return zipper.createBulk(directories, options) | ||
return zipster.fromPaths(directories, options) | ||
.should.be.rejectedWith(ZipsterError, error.message) | ||
}) | ||
}) | ||
describe('#fromDirectory', () => { | ||
const path = '/some/path/to/my/directory' | ||
const expectedPath = `${path}/${defaultFileName}.zip` | ||
beforeEach(() => { | ||
tmpdir.onFirstCall() | ||
.returns(path) | ||
createWriteStream.onFirstCall() | ||
.returns(stream) | ||
getArchiver.onFirstCall() | ||
.returns(archiver) | ||
archiver.pipe | ||
.onFirstCall() | ||
.returns() | ||
archiver.directory | ||
.onFirstCall() | ||
.returns() | ||
}) | ||
it('resolves with the output directory of the zipped directory', () => { | ||
archiver.finalize | ||
.onFirstCall() | ||
.resolves() | ||
return zipster.fromDirectory(path, options) | ||
.should.become(expectedPath) | ||
}) | ||
it('resolves and calls dependencies appropriately', () => { | ||
archiver.finalize | ||
.onFirstCall() | ||
.resolves() | ||
return zipster.fromDirectory(path, options) | ||
.should.be.fulfilled | ||
.then(() => { | ||
tmpdir.should.have.callCount(1) | ||
createWriteStream.should.have.been.calledOnceWithExactly(expectedPath) | ||
getArchiver.should.have.been.calledOnceWithExactly(options) | ||
archiver.pipe.should.have.been.calledOnceWithExactly(stream) | ||
archiver.directory.should.have.been.calledOnceWithExactly(path, false) | ||
archiver.finalize.should.have.callCount(1) | ||
}) | ||
}) | ||
it('resolves with the configured output location and name', () => { | ||
const options: Options = { | ||
format: Formats.ZIP_ENCRYPTABLE, | ||
password: 'testing', | ||
output: { | ||
path: '/foo/bar', | ||
name: 'foobar' | ||
} | ||
} | ||
const expectedPath = `${options.output.path}/${options.output.name}.zip` | ||
archiver.finalize | ||
.onFirstCall() | ||
.resolves() | ||
return zipster.fromDirectory(path, options) | ||
.should.become(expectedPath) | ||
.then(() => { | ||
getArchiver.should.have.been.calledOnceWithExactly(options) | ||
}) | ||
}) | ||
it('rejects with `ZipsterError` when an error occurs', () => { | ||
archiver.finalize | ||
.onFirstCall() | ||
.rejects(error) | ||
return zipster.fromDirectory(path, options) | ||
.should.be.rejectedWith(ZipsterError, error.message) | ||
}) | ||
}) | ||
describe('#fromPattern', () => { | ||
const pattern = 'foo*.txt' | ||
const path = '/path/to/my/file' | ||
const expectedOutputFile = `${path}/${defaultFileName}.zip` | ||
beforeEach(() => { | ||
tmpdir.onFirstCall() | ||
.returns(path) | ||
createWriteStream.onFirstCall() | ||
.returns(stream) | ||
getArchiver.onFirstCall() | ||
.returns(archiver) | ||
archiver.pipe | ||
.onFirstCall() | ||
.returns() | ||
archiver.glob | ||
.onFirstCall() | ||
.returns() | ||
}) | ||
it('resolves with the output location of the zipped files', () => { | ||
archiver.finalize | ||
.onFirstCall() | ||
.resolves() | ||
return zipster.fromPattern(path, pattern, options) | ||
.should.become(expectedOutputFile) | ||
}) | ||
it('resolves and calls dependencies appropriately', () => { | ||
const globOptions: IOptions = { | ||
cwd: path | ||
} | ||
archiver.finalize | ||
.onFirstCall() | ||
.resolves() | ||
return zipster.fromPattern(path, pattern, options) | ||
.should.be.fulfilled | ||
.then(() => { | ||
tmpdir.should.have.callCount(1) | ||
createWriteStream.should.have.been.calledOnceWithExactly(expectedOutputFile) | ||
getArchiver.should.have.been.calledOnceWithExactly(options) | ||
archiver.pipe.should.have.been.calledOnceWithExactly(stream) | ||
archiver.glob.should.have.been.calledOnceWithExactly(pattern, globOptions) | ||
archiver.finalize.should.have.callCount(1) | ||
}) | ||
}) | ||
it('rejects with `ZipsterError` when an error occurs finalizing the archive', () => { | ||
archiver.finalize | ||
.onFirstCall() | ||
.rejects(error) | ||
return zipster.fromPattern(path, pattern, options) | ||
.should.be.rejectedWith(ZipsterError, error.message) | ||
}) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
44996
807
175