diff --git a/index.d.ts b/index.d.ts index 6dbcc80..ebde748 100644 --- a/index.d.ts +++ b/index.d.ts @@ -10,6 +10,7 @@ declare namespace extract { defaultDirMode?: number; defaultFileMode?: number; onEntry?: (entry: Entry, zipfile: ZipFile) => void; + filter?: (entry: Entry, zipfile: ZipFile) => boolean; } } diff --git a/index.js b/index.js index 23384ea..dccb4db 100644 --- a/index.js +++ b/index.js @@ -37,6 +37,13 @@ class Extractor { }) this.zipfile.on('entry', async entry => { + if (this.opts.filter) { + if (!this.opts.filter(entry, this.zipfile)) { + this.zipfile.readEntry() + return + } + } + /* istanbul ignore if */ if (this.canceled) { debug('skipping entry', entry.fileName, { cancelled: this.canceled }) diff --git a/readme.md b/readme.md index 4ee7108..01c3153 100644 --- a/readme.md +++ b/readme.md @@ -45,6 +45,7 @@ async function main () { - `defaultDirMode` - integer - Directory Mode (permissions), defaults to `0o755` - `defaultFileMode` - integer - File Mode (permissions), defaults to `0o644` - `onEntry` - function - if present, will be called with `(entry, zipfile)`, entry is every entry from the zip file forwarded from the `entry` event from yauzl. `zipfile` is the `yauzl` instance +- `filter` - function - if present, will be called with `(entry, zipfile)`, entry is every entry from the zip file forwarded from the `entry` event from yauzl. `zipfile` is the `yauzl` instance. If the filter returns `true` for a given file it will be extracted, else it will be skipped. It is possible to change `entry.fileName` in the filter to change the location of output files. Default modes are only used if no permissions are set in the zip file. diff --git a/test/index.js b/test/index.js index a955a21..55b55c1 100644 --- a/test/index.js +++ b/test/index.js @@ -161,3 +161,20 @@ test('extract broken zip', async t => { message: 'invalid central directory file header signature: 0x2014b00' }) }) + +test('filter file output', async t => { + const dirPath = await mkdtemp(t, 'filter-files') + await extract(catsZip, { + dir: dirPath, + filter: (entry, zipFile) => { + if (entry.fileName !== 'a-cat.png') { + return false + } + entry.fileName = 'bored-cat.png' + entry.fileNameLength = entry.fileName.length + return true + } + }) + const entries = await fs.readdir(dirPath) + t.deepEqual(entries, ['bored-cat.png']) +})