87 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| '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);
 | |
| };
 |