diff --git a/changelog.md b/changelog.md index 4599021..85b37f9 100644 --- a/changelog.md +++ b/changelog.md @@ -39,4 +39,5 @@ ## Next +* Use `yauzl-clone` module for cloning yauzl object * Fix: Add `fd-slicer` dev dependency diff --git a/lib/cloneYauzl.js b/lib/cloneYauzl.js deleted file mode 100644 index 6c6f69c..0000000 --- a/lib/cloneYauzl.js +++ /dev/null @@ -1,34 +0,0 @@ -/* -------------------- - * yauzl-promise module - * Clone yauzl object - * ------------------*/ - -'use strict'; - -// Modules -const util = require('util'); - -// Exports -module.exports = function(yauzl) { - // Clone main object - yauzl = Object.assign({}, yauzl); - - // Subclass ZipFile - const ZipFileOriginal = yauzl.ZipFile; - function ZipFile() { - ZipFileOriginal.apply(this, arguments); - } - util.inherits(ZipFile, ZipFileOriginal); - yauzl.ZipFile = ZipFile; - - // Subclass Entry - const EntryOriginal = yauzl.Entry; - function Entry() { - EntryOriginal.apply(this, arguments); - } - util.inherits(Entry, EntryOriginal); - yauzl.Entry = Entry; - - // Return cloned copy of yauzl - return yauzl; -}; diff --git a/lib/index.js b/lib/index.js index fe0b6f5..559e013 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,11 +6,10 @@ // Modules const yauzlOriginal = require('yauzl'), - eventsIntercept = require('events-intercept'); + cloner = require('yauzl-clone'); // Imports const NativePromise = require('./promise'), - cloneYauzl = require('./cloneYauzl'), promisify = require('./promisify'); // Exports @@ -23,13 +22,11 @@ function use(Promise, yauzl, options) { if (!yauzl) yauzl = yauzlOriginal; // Clone yauzl unless `options.clone` false - if (options.clone) yauzl = cloneYauzl(yauzl); - - // Patch ZipFile prototype with events-intercept methods - const ZipFileProto = yauzl.ZipFile.prototype; - if (!ZipFileProto.intercept) { - eventsIntercept.patch(ZipFileProto); - ['_events', '_eventsCount', '_interceptors'].forEach(key => delete ZipFileProto[key]); + if (options.clone) { + yauzl = cloner.clone(yauzl, {subclassZipFile: true, subclassEntry: true}); + } else { + // Patch ZipFile prototype with events-intercept methods + cloner.clone(yauzl, {clone: false, eventsIntercept: true}); } // Add promisfied methods diff --git a/lib/promisify.js b/lib/promisify.js index 409e1a1..1b625ca 100644 --- a/lib/promisify.js +++ b/lib/promisify.js @@ -5,6 +5,9 @@ 'use strict'; +// Modules +const cloner = require('yauzl-clone'); + // Constants const STATE = Symbol(), STORED_ERROR = Symbol(); @@ -14,10 +17,10 @@ module.exports = (yauzl, Promise) => { const {ZipFile, Entry} = yauzl; // Promisify open + from... methods - promisifyMethod(yauzl, Promise, 'open', 1); - promisifyMethod(yauzl, Promise, 'fromFd', 1); - promisifyMethod(yauzl, Promise, 'fromBuffer', 1); - promisifyMethod(yauzl, Promise, 'fromRandomAccessReader', 2); + promisifyMethod(yauzl, Promise, 'open'); + promisifyMethod(yauzl, Promise, 'fromFd'); + promisifyMethod(yauzl, Promise, 'fromBuffer'); + promisifyMethod(yauzl, Promise, 'fromRandomAccessReader'); // Promisify `close` method promisifyClose(ZipFile, Promise); @@ -42,42 +45,24 @@ module.exports = (yauzl, Promise) => { /* * Promisify open/from... method */ -function promisifyMethod(yauzl, Promise, fnName, optionsArg) { - const original = yauzl[fnName], - cbArg = optionsArg + 1; - - yauzl[fnName] = function() { - return new Promise((resolve, reject) => { - const args = Array.prototype.slice.call(arguments); - args[optionsArg] = Object.assign({}, args[optionsArg], {lazyEntries: true, autoClose: false}); - - args[cbArg] = (err, zipFile) => { - if (err) return reject(err); - opened(zipFile, resolve, fnName == 'fromBuffer', yauzl); - }; - - original.apply(this, args); - }); - }; +function promisifyMethod(yauzl, Promise, fnName) { + const fromBuffer = fnName == 'fromBuffer'; + + cloner.patch(yauzl, fnName, original => { + return function(path, totalSize, options) { + return new Promise((resolve, reject) => { + options = Object.assign({}, options, {lazyEntries: true, autoClose: false}); + + original(path, totalSize, options, (err, zipFile) => { + if (err) return reject(err); + opened(zipFile, resolve, fromBuffer, yauzl); + }); + }); + }; + }); } function opened(zipFile, resolve, fromBuffer, yauzl) { - // Convert to instance of ZipFile subclass - const {ZipFile} = yauzl; - if (!(zipFile instanceof ZipFile)) { - const zipFileInternal = zipFile; - zipFile = setPrototype(zipFile, ZipFile.prototype); - - // Forward events from internal ZipFile to exposed one - zipFileInternal.on('close', () => zipFile.emit('close')); - zipFileInternal.on('error', err => zipFile.emit('error', err)); - - // Remove event interceptors from internal ZipFile - // so `close` + `error` events fire on exposed zipFile instance - // NB `._interceptors` already copied to subclass instance above - if (zipFile._interceptors) zipFileInternal._interceptors = {}; - } - // For `.fromBuffer()` calls, adapt `reader` to emit close event if (fromBuffer) { zipFile.reader.unref = yauzl.RandomAccessReader.prototype.unref; @@ -177,15 +162,8 @@ function emittedEntry(entry) { clearState(this); - // Modify entry object - if (entry) { - // Convert to instance of Entry subclass - const {Entry} = this.constructor; - if (!(entry instanceof Entry)) entry = setPrototype(entry, Entry.prototype); - - // Set reference to zipFile on entry (used by `entry.openReadStream()`) - entry.zipFile = this; - } + // Set reference to zipFile on entry (used by `entry.openReadStream()`) + if (entry) entry.zipFile = this; // Resolve promise with entry state.resolve(entry); @@ -298,10 +276,6 @@ function entryOpenReadStream(options) { /* * Utility functions */ -function setPrototype(obj, proto) { - return Object.assign(Object.create(proto), obj); -} - function wrapFunctionToReturnPromise(fn, Promise) { return function() { try { diff --git a/package.json b/package.json index ac88469..22e6b19 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ "url": "https://github.com/overlookmotel/yauzl-promise/issues" }, "dependencies": { - "events-intercept": "^2.0.0", - "yauzl": "^2.9.1" + "yauzl": "^2.9.1", + "yauzl-clone": "^1.0.0" }, "devDependencies": { "bluebird": "^3.5.1",