@jeffy-g/unzip
Version:

100 lines • 2.65 kB
JavaScript
/*!
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Copyright (C) 2024 jeffy-g <hirotom1107@gmail.com>
Released under the MIT license
https://opensource.org/licenses/mit-license.php
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/// <reference path="./ffunzip.d.ts"/>
const fs = require("fs");
const path = require("path");
const fflate = require("fflate");
require("colors.ts");
/**
* push already created directries
* @type {Set<string>}
*/
const knownDirectories = new Set();
/**
* @param {string} parent
*/
const mkdirs = (parent) => {
if (!knownDirectories.has(parent)) {
fs.mkdirSync(parent, { recursive: true });
knownDirectories.add(parent);
}
};
/**
* @param {string} path
*/
const removeLastSlash = (path) => path.replace(/(\/|\\)$/, "");
/**
* @type {(destDir: string, promises: Promise<void>[], cb: (...args: any) => void) => TForEachCallback}
*/
const forEachCallback = (destDir, promises, cb) => ([filename, data]) => {
/**
* @see {@link knownDirectories push the dirs}
* @see {@link mkdirs check already created}
*/
const size = data.length;
const output = `${destDir}/${filename}`;
/** @type {TSimpleZipEntry} */
const info = {
state: "pending",
type: size ? "File" : "Folder",
path: filename,
size
};
if (!size) {
mkdirs(output);
info.state = "ignore";
cb(info);
return;
}
cb(info);
mkdirs(path.dirname(output));
promises.push(
fs.promises.writeFile(output, data, "binary").then(() => {
info.state = "write";
cb(info);
})
);
};
/**
* @param {string} fileName zip file path
* @param {string} destDir output directory path
* @param {TUnzipCallback} cb
*/
const unzipWithCallback = (fileName, destDir, cb) => {
fs.readFile(fileName, null, (err, data) => {
if (err) {
console.error(err);
return;
}
/** @type {(file: UnzipFileInfo) => boolean} */
const filter = (file) => {
cb({
state: "info",
type: file.size ? "File" : "Folder",
path: file.name,
size: file.size
});
return true;
};
destDir = removeLastSlash(destDir);
fflate.unzip(data, { filter }, async (err, unzipped) => {
if (err) {
console.error(err);
return;
}
/** @type {Promise<void>[]} */
const promises = [];
Object.entries(unzipped).forEach(forEachCallback(destDir, promises, cb));
await Promise.all(promises);
cb(fileName);
knownDirectories.clear();
});
});
};
unzipWithCallback.version = "v1.1.13";
module.exports = unzipWithCallback;