'use strict'; const fileType = require('file-type'); const getStream = require('get-stream'); const pify = require('pify'); const yauzl = require('yauzl'); const getType = (entry, mode) => { const IFMT = 61440; const IFDIR = 16384; const IFLNK = 40960; const madeBy = entry.versionMadeBy >> 8; if ((mode & IFMT) === IFLNK) { return 'symlink'; } if ((mode & IFMT) === IFDIR || (madeBy === 0 && entry.externalFileAttributes === 16)) { return 'directory'; } return 'file'; }; const extractEntry = (entry, zip) => { const file = { mode: (entry.externalFileAttributes >> 16) & 0xFFFF, mtime: entry.getLastModDate(), path: entry.fileName }; file.type = getType(entry, file.mode); if (file.mode === 0 && file.type === 'directory') { file.mode = 493; } if (file.mode === 0) { file.mode = 420; } return pify(zip.openReadStream.bind(zip))(entry) .then(getStream.buffer) .then(buf => { file.data = buf; if (file.type === 'symlink') { file.linkname = buf.toString(); } return file; }) .catch(err => { zip.close(); throw err; }); }; const extractFile = zip => new Promise((resolve, reject) => { const files = []; zip.readEntry(); zip.on('entry', entry => { extractEntry(entry, zip) .catch(reject) .then(file => { files.push(file); zip.readEntry(); }); }); zip.on('error', reject); zip.on('end', () => resolve(files)); }); module.exports = () => buf => { if (!Buffer.isBuffer(buf)) { return Promise.reject(new TypeError(`Expected a Buffer, got ${typeof buf}`)); } if (!fileType(buf) || fileType(buf).ext !== 'zip') { return Promise.resolve([]); } return pify(yauzl.fromBuffer)(buf, {lazyEntries: true}).then(extractFile); };