read-excel-file
Version:
Read `.xlsx` files in a web browser or in Node.js
123 lines (121 loc) • 5.17 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = unzipFromStream;
var _buffer = require("buffer");
var _unzipper = _interopRequireDefault(require("unzipper"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
// `unzipper` has a bug when it doesn't include "@aws-sdk/client-s3" package in the `dependencies`
// which causes some "bundlers" throw an error.
// https://github.com/ZJONSSON/node-unzipper/issues/330
//
// One workaround is to install "@aws-sdk/client-s3" package manually, which would still lead to increased bundle size.
// If the code is bundled for server-side-use only, that is will not be used in a web browser,
// then the increased bundle size would not be an issue.
//
// Another workaround could be to "alias" "@aws-sdk/client-s3" package in a "bundler" configuration file
// with a path to a `*.js` file containing just "export default null". But that kind of a workaround would also
// result in errors when using other packages that `import` anything from "@aws-sdk/client-s3" package,
// so it's not really a workaround but more of a ticking bomb.
//
// Althernatively, it could use `fflate` if someone writes an example of handling a Node.js stream.
// https://github.com/101arrowz/fflate/issues/251
/**
* Reads `*.zip` file contents.
* @param {Stream} stream
* @return {Promise<Record<string,Buffer>>} Resolves to an object holding `*.zip` file entries. P.S. `Buffer` is a `Uint8Array`.
*/
function unzipFromStream(stream) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
filter = _ref.filter;
// The `files` object stores the files and their contents.
var files = {};
return new Promise(function (resolve, reject) {
var promises = [];
var errored = false;
var onError = function onError(error) {
if (!errored) {
errored = true;
reject(error);
}
};
stream
// This first "error" listener catches the original stream errors.
//
// That's because the .pipe() method does not automatically propagate errors
// from a source (input) stream to the destination stream or the end of the pipeline.
// You would need to attach an 'error' event handler to each stream in the chain.
//
// A more convenient alternative would be to use `stream.pipeline()` function:
// `pipeline(stream1, stream2, (error) => { ... })`
//
.on('error', onError)
// Pipe the input stream through the unzipper stream.
.pipe(_unzipper["default"].Parse())
// This second "error" listener catches the unzipper stream errors.
//
// That's because the .pipe() method does not automatically propagate errors
// from a source (input) stream to the destination stream or the end of the pipeline.
// You would need to attach an 'error' event handler to each stream in the chain.
//
// A more convenient alternative would be to use `stream.pipeline()` function:
// `pipeline(stream1, stream2, (error) => { ... })`
//
.on('error', onError)
// The unzipper stream is closed when all `entries` have been reported.
.on('finish', function () {
if (!errored) {
// Wait for all `entries` to be read.
// The second argument of `.then()` function is not required
// but I didn't remove it just to potentially prevent any potential silly bugs
// in case of some potential changes in some potential future.
Promise.all(promises).then(function () {
resolve(files);
}, onError);
}
}).on('entry', function (entry) {
// See if this file should be ignored.
var ignore = false;
// `entry.type` could be 'Directory' or 'File'.
// Ignore anything except files.
if (entry.type === 'Directory') {
ignore = true;
}
if (errored) {
ignore = true;
}
if (filter) {
if (!filter({
path: entry.path
})) {
ignore = true;
}
}
// If this file should be ignored.
if (ignore) {
// Call `entry.autodrain()` when you do not intend to process a specific `entry`'s raw data.
// Otherwise, if an `entry` is not consumed (via .pipe(), .buffer(), or .autodrain()),
// the stream will halt, preventing further file processing.
entry.autodrain().on('error', onError);
return;
}
var chunks = [];
promises.push(new Promise(function (resolve) {
// `entry` seems to be a generic Node.js stream.
// `entry.pipe()` pipes the file contents to a stream.
// `entry.stream()` returns a readable stream.
// `entry.buffer()` returns a promise that resolves to a `Buffer` with the file contents.
entry.on('data', function (data) {
chunks.push(data);
}).on('error', function (error) {
onError(error);
}).on('finish', function () {
files[entry.path] = _buffer.Buffer.concat(chunks);
resolve();
});
}));
});
});
}
//# sourceMappingURL=unzipFromStream.js.map