read-excel-file 9.2.0 → 9.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitlab-ci.yml +1 -1
- package/CHANGELOG.md +5 -0
- package/README.md +153 -50
- package/bundle/read-excel-file.min.js +1 -1
- package/bundle/read-excel-file.min.js.map +1 -1
- package/bundle/read-excel-file.min.old.js +2 -0
- package/bundle/read-excel-file.min.old.js.map +1 -0
- package/commonjs/export/convertValuesFromUint8ArraysToStrings.js +3 -0
- package/commonjs/export/convertValuesFromUint8ArraysToStrings.js.map +1 -1
- package/commonjs/export/parseSheet.js +12 -9
- package/commonjs/export/parseSheet.js.map +1 -1
- package/commonjs/export/readSheetBrowser.js +6 -2
- package/commonjs/export/readSheetBrowser.js.map +1 -1
- package/commonjs/export/readSheetNode.js +6 -2
- package/commonjs/export/readSheetNode.js.map +1 -1
- package/commonjs/export/readSheetUniversal.js +14 -2
- package/commonjs/export/readSheetUniversal.js.map +1 -1
- package/commonjs/export/readSheetWebWorker.js +12 -2
- package/commonjs/export/readSheetWebWorker.js.map +1 -1
- package/commonjs/export/readXlsxFileBrowser.js +6 -2
- package/commonjs/export/readXlsxFileBrowser.js.map +1 -1
- package/commonjs/export/readXlsxFileNode.js +6 -2
- package/commonjs/export/readXlsxFileNode.js.map +1 -1
- package/commonjs/export/readXlsxFileUniversal.js +14 -2
- package/commonjs/export/readXlsxFileUniversal.js.map +1 -1
- package/commonjs/export/readXlsxFileWebWorker.js +12 -2
- package/commonjs/export/readXlsxFileWebWorker.js.map +1 -1
- package/commonjs/export/unpackXlsxFileBrowser.js +29 -6
- package/commonjs/export/unpackXlsxFileBrowser.js.map +1 -1
- package/commonjs/export/unpackXlsxFileNode.js +6 -0
- package/commonjs/export/unpackXlsxFileNode.js.map +1 -1
- package/commonjs/export/unpackXlsxFileUniversal.js +6 -0
- package/commonjs/export/unpackXlsxFileUniversal.js.map +1 -1
- package/commonjs/export/unpackXlsxFileWebWorker.js +14 -0
- package/commonjs/export/unpackXlsxFileWebWorker.js.map +1 -0
- package/commonjs/parseSheetData/parseSheetData.js +6 -6
- package/commonjs/parseSheetData/parseSheetData.js.map +1 -1
- package/commonjs/utility/checkpoint.js +33 -0
- package/commonjs/utility/checkpoint.js.map +1 -0
- package/commonjs/utility/isObject.js +15 -0
- package/commonjs/utility/isObject.js.map +1 -0
- package/commonjs/utility/isPromise.js +18 -0
- package/commonjs/utility/isPromise.js.map +1 -0
- package/commonjs/xlsx/convertCellsToData2dArray.js +0 -3
- package/commonjs/xlsx/convertCellsToData2dArray.js.map +1 -1
- package/commonjs/xlsx/isDateFormatStyle.js +2 -2
- package/commonjs/xlsx/isDateFormatStyle.js.map +1 -1
- package/commonjs/xlsx/parseCell.js +89 -24
- package/commonjs/xlsx/parseCell.js.map +1 -1
- package/{modules/xlsx/parseCellCoordinates.js → commonjs/xlsx/parseCellAddress.js} +18 -7
- package/commonjs/xlsx/parseCellAddress.js.map +1 -0
- package/commonjs/xlsx/parseCellValue.js +7 -23
- package/commonjs/xlsx/parseCellValue.js.map +1 -1
- package/commonjs/xlsx/parseFilePaths.js +31 -32
- package/commonjs/xlsx/parseFilePaths.js.map +1 -1
- package/commonjs/xlsx/parseNumber.js +20 -0
- package/commonjs/xlsx/parseNumber.js.map +1 -0
- package/commonjs/xlsx/parseSharedString.js +64 -0
- package/commonjs/xlsx/parseSharedString.js.map +1 -0
- package/commonjs/xlsx/parseSharedStrings.js +45 -5
- package/commonjs/xlsx/parseSharedStrings.js.map +1 -1
- package/commonjs/xlsx/parseSheet.js +93 -9
- package/commonjs/xlsx/parseSheet.js.map +1 -1
- package/commonjs/xlsx/parseSheetData.js +68 -0
- package/commonjs/xlsx/parseSheetData.js.map +1 -0
- package/commonjs/xlsx/parseSpreadsheetContents.js +244 -43
- package/commonjs/xlsx/parseSpreadsheetContents.js.map +1 -1
- package/commonjs/xlsx/parseSpreadsheetInfo.js +67 -36
- package/commonjs/xlsx/parseSpreadsheetInfo.js.map +1 -1
- package/commonjs/xlsx/parseStyles.js +89 -36
- package/commonjs/xlsx/parseStyles.js.map +1 -1
- package/commonjs/xml/dom.js +2 -1
- package/commonjs/xml/dom.js.map +1 -1
- package/commonjs/xml/parseXmlStream.js +14 -0
- package/commonjs/xml/parseXmlStream.js.map +1 -0
- package/commonjs/xml/parseXmlStream.sax.js +109 -0
- package/commonjs/xml/parseXmlStream.sax.js.map +1 -0
- package/commonjs/xml/parseXmlStream.saxen.code.js +953 -0
- package/commonjs/xml/parseXmlStream.saxen.code.js.map +1 -0
- package/commonjs/xml/parseXmlStream.saxen.js +85 -0
- package/commonjs/xml/parseXmlStream.saxen.js.map +1 -0
- package/commonjs/xml/xlsx.js +75 -40
- package/commonjs/xml/xlsx.js.map +1 -1
- package/commonjs/zip/unzipFromArrayBuffer.js +5 -14
- package/commonjs/zip/unzipFromArrayBuffer.js.map +1 -1
- package/commonjs/zip/unzipFromStream.fflate.js +154 -25
- package/commonjs/zip/unzipFromStream.fflate.js.map +1 -1
- package/commonjs/zip/unzipFromStream.js.map +1 -1
- package/commonjs/zip/unzipFromStream.unzipper.js +37 -26
- package/commonjs/zip/unzipFromStream.unzipper.js.map +1 -1
- package/modules/export/convertValuesFromUint8ArraysToStrings.js +2 -0
- package/modules/export/convertValuesFromUint8ArraysToStrings.js.map +1 -1
- package/modules/export/parseSheet.js +12 -9
- package/modules/export/parseSheet.js.map +1 -1
- package/modules/export/readSheetBrowser.js +5 -2
- package/modules/export/readSheetBrowser.js.map +1 -1
- package/modules/export/readSheetNode.js +5 -2
- package/modules/export/readSheetNode.js.map +1 -1
- package/modules/export/readSheetUniversal.js +14 -2
- package/modules/export/readSheetUniversal.js.map +1 -1
- package/modules/export/readSheetWebWorker.js +12 -2
- package/modules/export/readSheetWebWorker.js.map +1 -1
- package/modules/export/readXlsxFileBrowser.js +5 -2
- package/modules/export/readXlsxFileBrowser.js.map +1 -1
- package/modules/export/readXlsxFileNode.js +5 -2
- package/modules/export/readXlsxFileNode.js.map +1 -1
- package/modules/export/readXlsxFileUniversal.js +14 -2
- package/modules/export/readXlsxFileUniversal.js.map +1 -1
- package/modules/export/readXlsxFileWebWorker.js +12 -2
- package/modules/export/readXlsxFileWebWorker.js.map +1 -1
- package/modules/export/unpackXlsxFileBrowser.js +26 -6
- package/modules/export/unpackXlsxFileBrowser.js.map +1 -1
- package/modules/export/unpackXlsxFileNode.js +3 -0
- package/modules/export/unpackXlsxFileNode.js.map +1 -1
- package/modules/export/unpackXlsxFileUniversal.js +3 -0
- package/modules/export/unpackXlsxFileUniversal.js.map +1 -1
- package/modules/export/unpackXlsxFileWebWorker.js +6 -0
- package/modules/export/unpackXlsxFileWebWorker.js.map +1 -0
- package/modules/parseSheetData/parseSheetData.js +4 -4
- package/modules/parseSheetData/parseSheetData.js.map +1 -1
- package/modules/utility/checkpoint.js +25 -0
- package/modules/utility/checkpoint.js.map +1 -0
- package/modules/utility/isObject.js +9 -0
- package/modules/utility/isObject.js.map +1 -0
- package/modules/utility/isPromise.js +12 -0
- package/modules/utility/isPromise.js.map +1 -0
- package/modules/xlsx/convertCellsToData2dArray.js +0 -3
- package/modules/xlsx/convertCellsToData2dArray.js.map +1 -1
- package/modules/xlsx/isDateFormatStyle.js +2 -2
- package/modules/xlsx/isDateFormatStyle.js.map +1 -1
- package/modules/xlsx/parseCell.js +85 -24
- package/modules/xlsx/parseCell.js.map +1 -1
- package/{commonjs/xlsx/parseCellCoordinates.js → modules/xlsx/parseCellAddress.js} +12 -13
- package/modules/xlsx/parseCellAddress.js.map +1 -0
- package/modules/xlsx/parseCellValue.js +7 -23
- package/modules/xlsx/parseCellValue.js.map +1 -1
- package/modules/xlsx/parseFilePaths.js +31 -33
- package/modules/xlsx/parseFilePaths.js.map +1 -1
- package/modules/xlsx/parseNumber.js +14 -0
- package/modules/xlsx/parseNumber.js.map +1 -0
- package/modules/xlsx/parseSharedString.js +55 -0
- package/modules/xlsx/parseSharedString.js.map +1 -0
- package/modules/xlsx/parseSharedStrings.js +46 -5
- package/modules/xlsx/parseSharedStrings.js.map +1 -1
- package/modules/xlsx/parseSheet.js +91 -9
- package/modules/xlsx/parseSheet.js.map +1 -1
- package/modules/xlsx/parseSheetData.js +55 -0
- package/modules/xlsx/parseSheetData.js.map +1 -0
- package/modules/xlsx/parseSpreadsheetContents.js +242 -43
- package/modules/xlsx/parseSpreadsheetContents.js.map +1 -1
- package/modules/xlsx/parseSpreadsheetInfo.js +67 -37
- package/modules/xlsx/parseSpreadsheetInfo.js.map +1 -1
- package/modules/xlsx/parseStyles.js +88 -36
- package/modules/xlsx/parseStyles.js.map +1 -1
- package/modules/xml/dom.js +2 -1
- package/modules/xml/dom.js.map +1 -1
- package/modules/xml/parseXmlStream.js +18 -0
- package/modules/xml/parseXmlStream.js.map +1 -0
- package/modules/xml/parseXmlStream.sax.js +103 -0
- package/modules/xml/parseXmlStream.sax.js.map +1 -0
- package/modules/xml/parseXmlStream.saxen.code.js +947 -0
- package/modules/xml/parseXmlStream.saxen.code.js.map +1 -0
- package/modules/xml/parseXmlStream.saxen.js +79 -0
- package/modules/xml/parseXmlStream.saxen.js.map +1 -0
- package/modules/xml/xlsx.js +72 -36
- package/modules/xml/xlsx.js.map +1 -1
- package/modules/zip/unzipFromArrayBuffer.js +5 -14
- package/modules/zip/unzipFromArrayBuffer.js.map +1 -1
- package/modules/zip/unzipFromStream.fflate.js +157 -24
- package/modules/zip/unzipFromStream.fflate.js.map +1 -1
- package/modules/zip/unzipFromStream.js +56 -2
- package/modules/zip/unzipFromStream.js.map +1 -1
- package/modules/zip/unzipFromStream.unzipper.js +38 -26
- package/modules/zip/unzipFromStream.unzipper.js.map +1 -1
- package/package.json +4 -6
- package/commonjs/xlsx/parseCellCoordinates.js.map +0 -1
- package/commonjs/xlsx/parseCells.js +0 -34
- package/commonjs/xlsx/parseCells.js.map +0 -1
- package/commonjs/xlsx/parseSheetDimensions.js +0 -43
- package/commonjs/xlsx/parseSheetDimensions.js.map +0 -1
- package/commonjs/xml/xml.js +0 -13
- package/commonjs/xml/xml.js.map +0 -1
- package/commonjs/xml/xmlBrowser.js +0 -17
- package/commonjs/xml/xmlBrowser.js.map +0 -1
- package/commonjs/xml/xpath/xlsx-xpath.js +0 -92
- package/commonjs/xml/xpath/xlsx-xpath.js.map +0 -1
- package/commonjs/xml/xpath/xpathBrowser.js +0 -33
- package/commonjs/xml/xpath/xpathBrowser.js.map +0 -1
- package/commonjs/xml/xpath/xpathNode.js +0 -16
- package/commonjs/xml/xpath/xpathNode.js.map +0 -1
- package/modules/xlsx/parseCellCoordinates.js.map +0 -1
- package/modules/xlsx/parseCells.js +0 -27
- package/modules/xlsx/parseCells.js.map +0 -1
- package/modules/xlsx/parseSheetDimensions.js +0 -37
- package/modules/xlsx/parseSheetDimensions.js.map +0 -1
- package/modules/xml/xml.js +0 -7
- package/modules/xml/xml.js.map +0 -1
- package/modules/xml/xmlBrowser.js +0 -11
- package/modules/xml/xmlBrowser.js.map +0 -1
- package/modules/xml/xpath/xlsx-xpath.js +0 -73
- package/modules/xml/xpath/xlsx-xpath.js.map +0 -1
- package/modules/xml/xpath/xpathBrowser.js +0 -27
- package/modules/xml/xpath/xpathBrowser.js.map +0 -1
- package/modules/xml/xpath/xpathNode.js +0 -9
- package/modules/xml/xpath/xpathNode.js.map +0 -1
|
@@ -6,12 +6,32 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports["default"] = unzipFromStream;
|
|
7
7
|
var _fflate = require("fflate");
|
|
8
8
|
var _nodeBuffer = require("node:buffer");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
var _nodeZlib = _interopRequireDefault(require("node:zlib"));
|
|
10
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
11
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
12
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
13
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
14
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
15
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
16
|
+
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
|
|
17
|
+
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } // Considerations:
|
|
18
|
+
//
|
|
19
|
+
// * `fflate` uses a pure-javascript implementation of `.zip` compression/decompression by default.
|
|
20
|
+
// This pure-javascript implementation is about 2x slower than Node.js's "native" `zlib` module.
|
|
21
|
+
// This issue is worked around by "marrying" `fflate` with Node.js's `zlib` "native" module through some tinkering.
|
|
22
|
+
// https://github.com/101arrowz/fflate/issues/284
|
|
23
|
+
//
|
|
24
|
+
// * Even though `fflate` implements a "streaming" mode of its own,
|
|
25
|
+
// it does not implement Node.js streams "contract", i.e. it just unzips the archive
|
|
26
|
+
// as fast as it can consume it from the input stream, without throttling the data throughput
|
|
27
|
+
// in cases when the input data flows faster than `fflate` can process it. This means that
|
|
28
|
+
// in the "worst case" scenario when `fflate`'s decompressor is unable to keep up with the
|
|
29
|
+
// data influx, it would "buffer" the entire `.zip` archive in RAM until it's processed.
|
|
30
|
+
// And while this is no big deal by any means, it's still not as elegant as adhering to
|
|
31
|
+
// Node.js streaming protocol.
|
|
12
32
|
// This code was originally submitted by Stian Jensen.
|
|
13
33
|
// https://github.com/catamphetamine/read-excel-file/pull/122
|
|
14
|
-
|
|
34
|
+
// https://github.com/catamphetamine/read-excel-file/pull/123
|
|
15
35
|
// A `*.zip` file consists of individual file entries with the "total" summary section
|
|
16
36
|
// placed at the end of the file rather than at the start of it, which was originally done
|
|
17
37
|
// to allow for easy append of data to a given `.zip` file.
|
|
@@ -36,10 +56,12 @@ var _nodeBuffer = require("node:buffer");
|
|
|
36
56
|
//
|
|
37
57
|
// When the "summary" section is reached, we assume that the archive has ended.
|
|
38
58
|
//
|
|
39
|
-
// To read a `.zip` archive, the code uses `fflate`'s `Unzip` class
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
59
|
+
// To read a `.zip` archive, the code uses `fflate`'s `Unzip` class.
|
|
60
|
+
// The actual decompression could be performed either by using
|
|
61
|
+
// `fflate`'s pure-javascript `UnzipInflate` implementation, which is
|
|
62
|
+
// about 2x slower than Node.js's "native" module `zlib`,
|
|
63
|
+
// or it could use the aforementioned `zlib` module as a drop-in replacement
|
|
64
|
+
// (with some tinkering).
|
|
43
65
|
//
|
|
44
66
|
// The `Unzip` class doesn't speak the Node.js stream interface, and `fflate`'s readme
|
|
45
67
|
// doesn't include a clear "reading a `.zip` file from a Node.js stream" section.
|
|
@@ -54,6 +76,24 @@ var _nodeBuffer = require("node:buffer");
|
|
|
54
76
|
// https://github.com/101arrowz/fflate/issues/277
|
|
55
77
|
// So just the regular `UnzipInflate` is used here.
|
|
56
78
|
//
|
|
79
|
+
// import { AsyncUnzipInflate, UnzipInflate } from 'fflate'
|
|
80
|
+
// Native `zlib` is faster than `UnzipInflate`.
|
|
81
|
+
// * When decompressing a `1 MB` `.xlsx` file, the decompression time is `100 ms`
|
|
82
|
+
// when using `zlib` decompressor and `150 ms` when using `fflate` "sync" decompressor.
|
|
83
|
+
// * When decompressing a `10 MB` `.xlsx` file, the decompression time is `500 ms`
|
|
84
|
+
// when using `zlib` decompressor and `650 ms` when using `fflate` "sync" decompressor.
|
|
85
|
+
// * When decompressing a `50 MB` `.xlsx` file, the decompression time is `2800 ms`
|
|
86
|
+
// when using `zlib` decompressor and `3600 ms` when using `fflate` "sync" decompressor.
|
|
87
|
+
var USE_ZLIB_DECOMPRESSOR = true;
|
|
88
|
+
|
|
89
|
+
// `AsyncZipInflate` is faster than `UnzipInflate` for `.xlsx` files that're larger
|
|
90
|
+
// than a few megabytes.
|
|
91
|
+
// * When decompressing a `1 MB` `.xlsx` file, the decompression time is `150 ms`
|
|
92
|
+
// when using "sync" decompressor and `170 ms` when using "async" decompressor.
|
|
93
|
+
// * When decompressing a `10 MB` `.xlsx` file, the decompression time is about the same.
|
|
94
|
+
// * When decompressing a `50 MB` `.xlsx` file, the decompression time is `3600 ms`
|
|
95
|
+
// when using "sync" decompressor and `3200 ms` when using "async" decompressor.
|
|
96
|
+
var USE_ASYNC_FFLATE_DECOMPRESSOR = false;
|
|
57
97
|
|
|
58
98
|
/**
|
|
59
99
|
* Reads `*.zip` file contents.
|
|
@@ -65,6 +105,31 @@ function unzipFromStream(stream) {
|
|
|
65
105
|
filter = _ref.filter;
|
|
66
106
|
// The `files` object stores the files and their contents.
|
|
67
107
|
var files = {};
|
|
108
|
+
var filesChunks = {};
|
|
109
|
+
var onFile = function onFile(filePath) {
|
|
110
|
+
// See if this file should be ignored.
|
|
111
|
+
// If it should, this entry won't be processed, i.e. `Unzip` will not try
|
|
112
|
+
// to decompress its data, and will just discard it.
|
|
113
|
+
if (filter && !filter({
|
|
114
|
+
path: filePath
|
|
115
|
+
})) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
filesChunks[filePath] = [];
|
|
119
|
+
};
|
|
120
|
+
var onFileData = function onFileData(filePath, chunk) {
|
|
121
|
+
filesChunks[filePath].push(chunk);
|
|
122
|
+
};
|
|
123
|
+
var onFileDataEnd = function onFileDataEnd(filePath) {
|
|
124
|
+
files[filePath] = _nodeBuffer.Buffer.concat(filesChunks[filePath]);
|
|
125
|
+
delete filesChunks[filePath];
|
|
126
|
+
};
|
|
127
|
+
return unzipFromStream_(stream, onFile, onFileData, onFileDataEnd).then(function () {
|
|
128
|
+
return files;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
var PROMISE_RESOLVE_VALUE = undefined;
|
|
132
|
+
function unzipFromStream_(stream, onFile, onFileData, onFileDataEnd) {
|
|
68
133
|
return new Promise(function (resolve, reject) {
|
|
69
134
|
var errored = false;
|
|
70
135
|
var onError = function onError(error) {
|
|
@@ -73,6 +138,19 @@ function unzipFromStream(stream) {
|
|
|
73
138
|
reject(error);
|
|
74
139
|
}
|
|
75
140
|
};
|
|
141
|
+
|
|
142
|
+
// The native `zlib` decoder finishes inflating an entry asynchronously, so
|
|
143
|
+
// the archive's `end` event can fire while entries are still decompressing.
|
|
144
|
+
// It counts "decompression still in-progress" entries the decompression for which
|
|
145
|
+
// has started but not yet finished, and the main promise only resolves once
|
|
146
|
+
// the input stream has ended *and* every entry is done decompressing.
|
|
147
|
+
var stillDecompressingEntriesCount = 0;
|
|
148
|
+
var noMoreEntries = false;
|
|
149
|
+
var resolveIfDone = function resolveIfDone() {
|
|
150
|
+
if (!errored && noMoreEntries && stillDecompressingEntriesCount === 0) {
|
|
151
|
+
resolve(PROMISE_RESOLVE_VALUE);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
76
154
|
var _createZipFileValidat = createZipFileValidator(function (isValid) {
|
|
77
155
|
if (!isValid) {
|
|
78
156
|
onError(new Error('Invalid `.zip` archive'));
|
|
@@ -94,26 +172,22 @@ function unzipFromStream(stream) {
|
|
|
94
172
|
if (entry.name.endsWith('/')) {
|
|
95
173
|
return;
|
|
96
174
|
}
|
|
97
|
-
|
|
98
|
-
// See if this file should be ignored.
|
|
99
|
-
// If it should, this entry won't be processed, i.e. `Unzip` will not try
|
|
100
|
-
// to decompress its data, and will just discard it.
|
|
101
|
-
if (filter && !filter({
|
|
102
|
-
path: entry.name
|
|
103
|
-
})) {
|
|
175
|
+
if (onFile(entry.name) === false) {
|
|
104
176
|
return;
|
|
105
177
|
}
|
|
106
|
-
|
|
178
|
+
stillDecompressingEntriesCount++;
|
|
107
179
|
|
|
108
180
|
// `entry.ondata` is called with each decompressed chunk of the entry,
|
|
109
|
-
// and a final time with `isLast === true` once the entry is complete.
|
|
181
|
+
// and then a final time with `isLast === true` once the entry is complete.
|
|
110
182
|
entry.ondata = function (error, chunk, isLast) {
|
|
111
183
|
if (error) {
|
|
112
184
|
return onError(error);
|
|
113
185
|
}
|
|
114
|
-
|
|
186
|
+
onFileData(entry.name, chunk);
|
|
115
187
|
if (isLast) {
|
|
116
|
-
|
|
188
|
+
stillDecompressingEntriesCount--;
|
|
189
|
+
onFileDataEnd(entry.name);
|
|
190
|
+
resolveIfDone();
|
|
117
191
|
}
|
|
118
192
|
};
|
|
119
193
|
|
|
@@ -124,7 +198,7 @@ function unzipFromStream(stream) {
|
|
|
124
198
|
// Register the decompressor for the data that was compressed using
|
|
125
199
|
// `DEFLATE` compression algorithm (compression method `8`),
|
|
126
200
|
// which is what `.xlsx` files use.
|
|
127
|
-
unzip.register(
|
|
201
|
+
unzip.register(USE_ZLIB_DECOMPRESSOR ? NativeZlibInflate : USE_ASYNC_FFLATE_DECOMPRESSOR ? AsyncUnzipInflate : UnzipInflate);
|
|
128
202
|
stream
|
|
129
203
|
// Catch errors emitted from the input stream (for example, a file read error).
|
|
130
204
|
.on('error', onError)
|
|
@@ -143,9 +217,15 @@ function unzipFromStream(stream) {
|
|
|
143
217
|
return;
|
|
144
218
|
}
|
|
145
219
|
// Push the next data chunk to `fflate`'s `Unzip` class instance.
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
220
|
+
//
|
|
221
|
+
// The `.push()` function of `fflate`'s own `ZipInflate` decompressor is synchronous,
|
|
222
|
+
// meaning that by the time it returns, any complete files entries encountered so far
|
|
223
|
+
// have already been decompressed and populated in the `files` object.
|
|
224
|
+
//
|
|
225
|
+
// The `.push()` function of `NativeZlibInflate` decompressor is asynchronous,
|
|
226
|
+
// so it requires hacking around with the counter of "still being decompressed" entries
|
|
227
|
+
// in order to detect the actual finish of the archive's decompression process.
|
|
228
|
+
//
|
|
149
229
|
try {
|
|
150
230
|
unzip.push(chunk, false);
|
|
151
231
|
} catch (error) {
|
|
@@ -164,8 +244,12 @@ function unzipFromStream(stream) {
|
|
|
164
244
|
// Signal the end of the archive to `fflate`'s `Unzip` class instance.
|
|
165
245
|
// It will flush any remaining state in it.
|
|
166
246
|
unzip.push(new Uint8Array(0), true);
|
|
167
|
-
//
|
|
168
|
-
|
|
247
|
+
// The input stream has ended.
|
|
248
|
+
noMoreEntries = true;
|
|
249
|
+
// The entries may still be decompressing asynchronously.
|
|
250
|
+
// In that case, resolve once they all finish decompresssing.
|
|
251
|
+
// Or, resolve if all entries have already finished decompressing by now.
|
|
252
|
+
resolveIfDone();
|
|
169
253
|
} catch (error) {
|
|
170
254
|
onError(error);
|
|
171
255
|
}
|
|
@@ -206,4 +290,49 @@ function createZipFileValidator(onValidationResult) {
|
|
|
206
290
|
}
|
|
207
291
|
};
|
|
208
292
|
}
|
|
293
|
+
|
|
294
|
+
// An implemenation of a `DEFLATE` decompressor for `fflate`'s `Unzip` class
|
|
295
|
+
// that uses Node.js's "native" module `zlib`.
|
|
296
|
+
//
|
|
297
|
+
// It implements `fflate`'s decoder interface: `Unzip` constructs one decoder
|
|
298
|
+
// per each entry, sets `ondata(error, chunk, isLast)` callback on it, and feeds it
|
|
299
|
+
// the entry's compressed bytes by calling `push(chunk, isLast)` method.
|
|
300
|
+
//
|
|
301
|
+
// Unlike `fflate`'s synchronous `UnzipInflate` decoder, `zlib` decompresses asynchronously,
|
|
302
|
+
// so an entry only finishes some "ticks" after its last chunk of its data is `push()`ed
|
|
303
|
+
// by `fflate`'s `Unzip` class. To work around this issue, pending entries counter is used
|
|
304
|
+
// to track when the archive really finishes unpacking.
|
|
305
|
+
//
|
|
306
|
+
var NativeZlibInflate = /*#__PURE__*/function () {
|
|
307
|
+
function NativeZlibInflate() {
|
|
308
|
+
var _this = this;
|
|
309
|
+
_classCallCheck(this, NativeZlibInflate);
|
|
310
|
+
this.inflate = _nodeZlib["default"].createInflateRaw();
|
|
311
|
+
this.inflate.on('data', function (chunk) {
|
|
312
|
+
return _this.ondata(null, chunk, false);
|
|
313
|
+
});
|
|
314
|
+
this.inflate.on('end', function () {
|
|
315
|
+
return _this.ondata(null, new Uint8Array(0), true);
|
|
316
|
+
});
|
|
317
|
+
this.inflate.on('error', function (error) {
|
|
318
|
+
return _this.ondata(error, null, false);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
_createClass(NativeZlibInflate, [{
|
|
322
|
+
key: "push",
|
|
323
|
+
value: function push(chunk, isLast) {
|
|
324
|
+
this.inflate.write(_nodeBuffer.Buffer.from(chunk));
|
|
325
|
+
if (isLast) {
|
|
326
|
+
this.inflate.end();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}, {
|
|
330
|
+
key: "terminate",
|
|
331
|
+
value: function terminate() {
|
|
332
|
+
this.inflate.destroy();
|
|
333
|
+
}
|
|
334
|
+
}]);
|
|
335
|
+
return NativeZlibInflate;
|
|
336
|
+
}();
|
|
337
|
+
_defineProperty(NativeZlibInflate, "compression", 8);
|
|
209
338
|
//# sourceMappingURL=unzipFromStream.fflate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unzipFromStream.fflate.js","names":["_fflate","require","_nodeBuffer","unzipFromStream","stream","_ref","arguments","length","undefined","filter","files","Promise","resolve","reject","errored","onError","error","_createZipFileValidat","createZipFileValidator","isValid","Error","validateChunk","unzip","Unzip","entry","name","endsWith","path","chunks","ondata","chunk","isLast","push","Buffer","concat","start","register","UnzipInflate","on","Uint8Array","onValidationResult","firstBytesCount","firstBytes","firstBytesCheckResult","i"],"sources":["../../source/zip/unzipFromStream.fflate.js"],"sourcesContent":["// `fflate` uses a javascript-only implementation of `.zip` compression/decompression.\r\n// This means that it could likely be less performant than Node.js's \"native\" `zlib` module`.\r\n\r\n// This code was originally submitted by Stian Jensen.\r\n// https://github.com/catamphetamine/read-excel-file/pull/122\r\n\r\n// A `*.zip` file consists of individual file entries with the \"total\" summary section\r\n// placed at the end of the file rather than at the start of it, which was originally done\r\n// to allow for easy append of data to a given `.zip` file.\r\n// https://en.wikipedia.org/wiki/ZIP_(file_format)\r\n//\r\n// But this also means that reading a `*.zip` file from a stream can't really be done\r\n// using the \"officially recommended\" way of first reading the \"total\" summary section\r\n// and only then reading the individual file entries specified in that summary section.\r\n//\r\n// So in order to be able to read a `*.zip` file from a stream, some corners have to be cut.\r\n// For example, the \"total\" summary section is completely ignored and instead the reader\r\n// should adopt \"data recovery\" software approach — it should proactively \"scan\" the input stream\r\n// for individual file entries and handle them one-by-one as they come.\r\n//\r\n// Such approach doesn't seem to contradict with the XLSX specification\r\n// because an `*.xlsx` files is supposed to be a normal `.zip` archive\r\n// without any \"trickery\" such as \"deleted\" files or \"garbage\" data\r\n// hiding under the hood.\r\n//\r\n// So when handling `*.xlsx` file, we assume that each such file must start\r\n// with an individual file entry followed by another individual file entry, etc.\r\n//\r\n// When the \"summary\" section is reached, we assume that the archive has ended.\r\n//\r\n// To read a `.zip` archive, the code uses `fflate`'s `Unzip` class\r\n// with `UnzipInflate` decompression implementation to decompress the data\r\n// that was previously compressed using `DEFLATE` compressing algorithm,\r\n// which is what `*.xlsx` files use.\r\n//\r\n// The `Unzip` class doesn't speak the Node.js stream interface, and `fflate`'s readme\r\n// doesn't include a clear \"reading a `.zip` file from a Node.js stream\" section.\r\n// https://github.com/101arrowz/fflate/issues/251\r\n// Instead, the `Unzip` class has its own `push(chunk)` / `onfile` / `entry.ondata` protocol.\r\n// This code reads the binary input stream and forwards each chunk of it to `unzip.push()`,\r\n// and then collects the decompressed file entries.\r\n//\r\n// P.S. In the comments to `UnzipInflate` in `fflate` package, it says:\r\n// \"Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for better performance.\"\r\n// But there seems to be no `AsyncZipInflate` class in the `fflate` package.\r\n// https://github.com/101arrowz/fflate/issues/277\r\n// So just the regular `UnzipInflate` is used here.\r\n//\r\nimport { Unzip, UnzipInflate } from 'fflate'\r\n\r\nimport { Buffer } from 'node:buffer'\r\n\r\n/**\r\n * Reads `*.zip` file contents.\r\n * @param {Stream} stream\r\n * @return {Promise<Record<string,Buffer>>} Resolves to an object holding `*.zip` file entries. P.S. `Buffer` is a `Uint8Array`.\r\n */\r\nexport default function unzipFromStream(stream, { filter } = {}) {\r\n\t// The `files` object stores the files and their contents.\r\n\tconst files = {}\r\n\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tlet errored = false\r\n\r\n\t\tconst onError = (error) => {\r\n\t\t\tif (!errored) {\r\n\t\t\t\terrored = true\r\n\t\t\t\treject(error)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst { validateChunk } = createZipFileValidator((isValid) => {\r\n\t\t\tif (!isValid) {\r\n\t\t\t\tonError(new Error('Invalid `.zip` archive'))\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\t// `Unzip` discovers each individual file entry in the input data stream\r\n\t\t// and then calls the callback function for each such entry.\r\n\t\tconst unzip = new Unzip((entry) => {\r\n\t\t\t// If there already was an error while reading this `.zip` file,\r\n\t\t\t// ignore any follow-up entries.\r\n\t\t\tif (errored) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\r\n\t\t\t// Skip directory entries (their names end with a slash).\r\n\t\t\t// Only files are of any interest.\r\n\t\t\tif (entry.name.endsWith('/')) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\r\n\t\t\t// See if this file should be ignored.\r\n\t\t\t// If it should, this entry won't be processed, i.e. `Unzip` will not try\r\n\t\t\t// to decompress its data, and will just discard it.\r\n\t\t\tif (filter && !filter({ path: entry.name })) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\r\n\t\t\tconst chunks = []\r\n\r\n\t\t\t// `entry.ondata` is called with each decompressed chunk of the entry,\r\n\t\t\t// and a final time with `isLast === true` once the entry is complete.\r\n\t\t\tentry.ondata = (error, chunk, isLast) => {\r\n\t\t\t\tif (error) {\r\n\t\t\t\t\treturn onError(error)\r\n\t\t\t\t}\r\n\t\t\t\tchunks.push(chunk)\r\n\t\t\t\tif (isLast) {\r\n\t\t\t\t\tfiles[entry.name] = Buffer.concat(chunks)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Start decompressing this entry.\r\n\t\t\tentry.start()\r\n\t\t})\r\n\r\n\t\t// Register the decompressor for the data that was compressed using\r\n\t\t// `DEFLATE` compression algorithm (compression method `8`),\r\n\t\t// which is what `.xlsx` files use.\r\n\t\tunzip.register(UnzipInflate)\r\n\r\n\t\tstream\r\n\t\t\t// Catch errors emitted from the input stream (for example, a file read error).\r\n\t\t\t.on('error', onError)\r\n\t\t\t// When another chunk of data is read from the input stream.\r\n\t\t\t.on('data', (chunk) => {\r\n\t\t\t\t// If there already was an error while reading this `.zip` file,\r\n\t\t\t\t// ignore any follow-up data chunks.\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t\t// Validate the `.zip` archive as its data comes through.\r\n\t\t\t\tvalidateChunk(chunk)\r\n\t\t\t\t// If the `.zip` archive is found to be invalid, stop any further\r\n\t\t\t\t// processing of it.\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t\t// Push the next data chunk to `fflate`'s `Unzip` class instance.\r\n\t\t\t\t// The `.push()` function is synchronous, meaning that by the time it returns,\r\n\t\t\t\t// any complete files entries encountered so far have already been decompressed\r\n\t\t\t\t// and populated in the `files` object.\r\n\t\t\t\ttry {\r\n\t\t\t\t\tunzip.push(chunk, false)\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tonError(error)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t// When there's no more data in the input stream to consume,\r\n\t\t\t// finish reading the `.zip` archive.\r\n\t\t\t.on('end', () => {\r\n\t\t\t\t// If there were any errors when reading the `.zip` archive,\r\n\t\t\t\t// don't `resolve()` with anything.\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t\ttry {\r\n\t\t\t\t\t// Signal the end of the archive to `fflate`'s `Unzip` class instance.\r\n\t\t\t\t\t// It will flush any remaining state in it.\r\n\t\t\t\t\tunzip.push(new Uint8Array(0), true)\r\n\t\t\t\t\t// Resolve with the unzipped files.\r\n\t\t\t\t\tresolve(files)\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tonError(error)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t})\r\n}\r\n\r\n// Every section in a `.zip` archive is marked with 4 bytes, the first two of which\r\n// are `0x50` and `0x4B`, which reads \"PK\", referencing the initials of the inventor Phil Katz.\r\n//\r\n// It looks like `fflate`'s `Unzip` doesn't ever complain about whatever data is thrown at it.\r\n// Due to how `.zip` file format is defined, \"garbage\" data could be placed at various\r\n// places in it and it'd still be a valid `.zip` archive. It's likely that for this reason\r\n// `fflate` doesn't ever complain and simply emits no entries when fed any kind of invalid data.\r\n//\r\n// In order to introduce some basic validation, here we specifically demand\r\n// that a `.zip` archive must at least start with an individual file entry\r\n// because an `.xlsx` file creator softwared really shouldn't attempt doing\r\n// anything \"funny\" when writing a file, hence this adherence requirement.\r\n//\r\nfunction createZipFileValidator(onValidationResult) {\r\n\tconst firstBytesCount = 2\r\n\tconst firstBytes = []\r\n\tlet firstBytesCheckResult\r\n\treturn {\r\n\t\tvalidateChunk(chunk) {\r\n\t\t\tif (firstBytes.length < 2) {\r\n\t\t\t\tlet i = 0\r\n\t\t\t\twhile (i < chunk.length && i < firstBytesCount) {\r\n\t\t\t\t\tfirstBytes.push(chunk[i])\r\n\t\t\t\t\ti++\r\n\t\t\t\t}\r\n\t\t\t\tif (firstBytes.length === 2) {\r\n\t\t\t\t\tconst isValid = firstBytes[0] === 0x50 && firstBytes[1] === 0x4B\r\n\t\t\t\t\tonValidationResult(isValid)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"unzipFromStream.fflate.js","names":["_fflate","require","_nodeBuffer","_nodeZlib","_interopRequireDefault","obj","__esModule","_typeof","o","Symbol","iterator","constructor","prototype","_classCallCheck","instance","Constructor","TypeError","_defineProperties","target","props","i","length","descriptor","enumerable","configurable","writable","Object","defineProperty","_toPropertyKey","key","_createClass","protoProps","staticProps","_defineProperty","value","arg","_toPrimitive","String","input","hint","prim","toPrimitive","undefined","res","call","Number","USE_ZLIB_DECOMPRESSOR","USE_ASYNC_FFLATE_DECOMPRESSOR","unzipFromStream","stream","_ref","arguments","filter","files","filesChunks","onFile","filePath","path","onFileData","chunk","push","onFileDataEnd","Buffer","concat","unzipFromStream_","then","PROMISE_RESOLVE_VALUE","Promise","resolve","reject","errored","onError","error","stillDecompressingEntriesCount","noMoreEntries","resolveIfDone","_createZipFileValidat","createZipFileValidator","isValid","Error","validateChunk","unzip","Unzip","entry","name","endsWith","ondata","isLast","start","register","NativeZlibInflate","AsyncUnzipInflate","UnzipInflate","on","Uint8Array","onValidationResult","firstBytesCount","firstBytes","firstBytesCheckResult","_this","inflate","zlib","createInflateRaw","write","from","end","terminate","destroy"],"sources":["../../source/zip/unzipFromStream.fflate.js"],"sourcesContent":["// Considerations:\r\n//\r\n// * `fflate` uses a pure-javascript implementation of `.zip` compression/decompression by default.\r\n// This pure-javascript implementation is about 2x slower than Node.js's \"native\" `zlib` module.\r\n// This issue is worked around by \"marrying\" `fflate` with Node.js's `zlib` \"native\" module through some tinkering.\r\n// https://github.com/101arrowz/fflate/issues/284\r\n//\r\n// * Even though `fflate` implements a \"streaming\" mode of its own,\r\n// it does not implement Node.js streams \"contract\", i.e. it just unzips the archive\r\n// as fast as it can consume it from the input stream, without throttling the data throughput\r\n// in cases when the input data flows faster than `fflate` can process it. This means that\r\n// in the \"worst case\" scenario when `fflate`'s decompressor is unable to keep up with the\r\n// data influx, it would \"buffer\" the entire `.zip` archive in RAM until it's processed.\r\n// And while this is no big deal by any means, it's still not as elegant as adhering to\r\n// Node.js streaming protocol.\r\n\r\n// This code was originally submitted by Stian Jensen.\r\n// https://github.com/catamphetamine/read-excel-file/pull/122\r\n// https://github.com/catamphetamine/read-excel-file/pull/123\r\n\r\n// A `*.zip` file consists of individual file entries with the \"total\" summary section\r\n// placed at the end of the file rather than at the start of it, which was originally done\r\n// to allow for easy append of data to a given `.zip` file.\r\n// https://en.wikipedia.org/wiki/ZIP_(file_format)\r\n//\r\n// But this also means that reading a `*.zip` file from a stream can't really be done\r\n// using the \"officially recommended\" way of first reading the \"total\" summary section\r\n// and only then reading the individual file entries specified in that summary section.\r\n//\r\n// So in order to be able to read a `*.zip` file from a stream, some corners have to be cut.\r\n// For example, the \"total\" summary section is completely ignored and instead the reader\r\n// should adopt \"data recovery\" software approach — it should proactively \"scan\" the input stream\r\n// for individual file entries and handle them one-by-one as they come.\r\n//\r\n// Such approach doesn't seem to contradict with the XLSX specification\r\n// because an `*.xlsx` files is supposed to be a normal `.zip` archive\r\n// without any \"trickery\" such as \"deleted\" files or \"garbage\" data\r\n// hiding under the hood.\r\n//\r\n// So when handling `*.xlsx` file, we assume that each such file must start\r\n// with an individual file entry followed by another individual file entry, etc.\r\n//\r\n// When the \"summary\" section is reached, we assume that the archive has ended.\r\n//\r\n// To read a `.zip` archive, the code uses `fflate`'s `Unzip` class.\r\n// The actual decompression could be performed either by using\r\n// `fflate`'s pure-javascript `UnzipInflate` implementation, which is\r\n// about 2x slower than Node.js's \"native\" module `zlib`,\r\n// or it could use the aforementioned `zlib` module as a drop-in replacement\r\n// (with some tinkering).\r\n//\r\n// The `Unzip` class doesn't speak the Node.js stream interface, and `fflate`'s readme\r\n// doesn't include a clear \"reading a `.zip` file from a Node.js stream\" section.\r\n// https://github.com/101arrowz/fflate/issues/251\r\n// Instead, the `Unzip` class has its own `push(chunk)` / `onfile` / `entry.ondata` protocol.\r\n// This code reads the binary input stream and forwards each chunk of it to `unzip.push()`,\r\n// and then collects the decompressed file entries.\r\n//\r\n// P.S. In the comments to `UnzipInflate` in `fflate` package, it says:\r\n// \"Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for better performance.\"\r\n// But there seems to be no `AsyncZipInflate` class in the `fflate` package.\r\n// https://github.com/101arrowz/fflate/issues/277\r\n// So just the regular `UnzipInflate` is used here.\r\n//\r\nimport { Unzip } from 'fflate'\r\n// import { AsyncUnzipInflate, UnzipInflate } from 'fflate'\r\n\r\nimport { Buffer } from 'node:buffer'\r\nimport zlib from 'node:zlib'\r\n\r\n// Native `zlib` is faster than `UnzipInflate`.\r\n// * When decompressing a `1 MB` `.xlsx` file, the decompression time is `100 ms`\r\n// when using `zlib` decompressor and `150 ms` when using `fflate` \"sync\" decompressor.\r\n// * When decompressing a `10 MB` `.xlsx` file, the decompression time is `500 ms`\r\n// when using `zlib` decompressor and `650 ms` when using `fflate` \"sync\" decompressor.\r\n// * When decompressing a `50 MB` `.xlsx` file, the decompression time is `2800 ms`\r\n// when using `zlib` decompressor and `3600 ms` when using `fflate` \"sync\" decompressor.\r\nconst USE_ZLIB_DECOMPRESSOR = true\r\n\r\n// `AsyncZipInflate` is faster than `UnzipInflate` for `.xlsx` files that're larger\r\n// than a few megabytes.\r\n// * When decompressing a `1 MB` `.xlsx` file, the decompression time is `150 ms`\r\n// when using \"sync\" decompressor and `170 ms` when using \"async\" decompressor.\r\n// * When decompressing a `10 MB` `.xlsx` file, the decompression time is about the same.\r\n// * When decompressing a `50 MB` `.xlsx` file, the decompression time is `3600 ms`\r\n// when using \"sync\" decompressor and `3200 ms` when using \"async\" decompressor.\r\nconst USE_ASYNC_FFLATE_DECOMPRESSOR = false\r\n\r\n/**\r\n * Reads `*.zip` file contents.\r\n * @param {Stream} stream\r\n * @return {Promise<Record<string,Buffer>>} Resolves to an object holding `*.zip` file entries. P.S. `Buffer` is a `Uint8Array`.\r\n */\r\nexport default function unzipFromStream(stream, { filter } = {}) {\r\n\t// The `files` object stores the files and their contents.\r\n\tconst files = {}\r\n\tconst filesChunks = {}\r\n\r\n\tconst onFile = (filePath) => {\r\n\t\t// See if this file should be ignored.\r\n\t\t// If it should, this entry won't be processed, i.e. `Unzip` will not try\r\n\t\t// to decompress its data, and will just discard it.\r\n\t\tif (filter && !filter({ path: filePath })) {\r\n\t\t\treturn false\r\n\t\t}\r\n\t\tfilesChunks[filePath] = []\r\n\t}\r\n\r\n\tconst onFileData = (filePath, chunk) => {\r\n\t\tfilesChunks[filePath].push(chunk)\r\n\t}\r\n\r\n\tconst onFileDataEnd = (filePath) => {\r\n\t\tfiles[filePath] = Buffer.concat(filesChunks[filePath])\r\n\t\tdelete filesChunks[filePath]\r\n\t}\r\n\r\n\treturn unzipFromStream_(stream, onFile, onFileData, onFileDataEnd).then(() => {\r\n\t\treturn files\r\n\t})\r\n}\r\n\r\nconst PROMISE_RESOLVE_VALUE = undefined\r\n\r\nfunction unzipFromStream_(stream, onFile, onFileData, onFileDataEnd) {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tlet errored = false\r\n\r\n\t\tconst onError = (error) => {\r\n\t\t\tif (!errored) {\r\n\t\t\t\terrored = true\r\n\t\t\t\treject(error)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// The native `zlib` decoder finishes inflating an entry asynchronously, so\r\n\t\t// the archive's `end` event can fire while entries are still decompressing.\r\n\t\t// It counts \"decompression still in-progress\" entries the decompression for which\r\n\t\t// has started but not yet finished, and the main promise only resolves once\r\n\t\t// the input stream has ended *and* every entry is done decompressing.\r\n\t\tlet stillDecompressingEntriesCount = 0\r\n\t\tlet noMoreEntries = false\r\n\t\tconst resolveIfDone = () => {\r\n\t\t\tif (!errored && noMoreEntries && stillDecompressingEntriesCount === 0) {\r\n\t\t\t\tresolve(PROMISE_RESOLVE_VALUE)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst { validateChunk } = createZipFileValidator((isValid) => {\r\n\t\t\tif (!isValid) {\r\n\t\t\t\tonError(new Error('Invalid `.zip` archive'))\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\t// `Unzip` discovers each individual file entry in the input data stream\r\n\t\t// and then calls the callback function for each such entry.\r\n\t\tconst unzip = new Unzip((entry) => {\r\n\t\t\t// If there already was an error while reading this `.zip` file,\r\n\t\t\t// ignore any follow-up entries.\r\n\t\t\tif (errored) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\r\n\t\t\t// Skip directory entries (their names end with a slash).\r\n\t\t\t// Only files are of any interest.\r\n\t\t\tif (entry.name.endsWith('/')) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\r\n\t\t\tif (onFile(entry.name) === false) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\r\n\t\t\tstillDecompressingEntriesCount++\r\n\r\n\t\t\t// `entry.ondata` is called with each decompressed chunk of the entry,\r\n\t\t\t// and then a final time with `isLast === true` once the entry is complete.\r\n\t\t\tentry.ondata = (error, chunk, isLast) => {\r\n\t\t\t\tif (error) {\r\n\t\t\t\t\treturn onError(error)\r\n\t\t\t\t}\r\n\t\t\t\tonFileData(entry.name, chunk)\r\n\t\t\t\tif (isLast) {\r\n\t\t\t\t\tstillDecompressingEntriesCount--\r\n\t\t\t\t\tonFileDataEnd(entry.name)\r\n\t\t\t\t\tresolveIfDone()\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Start decompressing this entry.\r\n\t\t\tentry.start()\r\n\t\t})\r\n\r\n\t\t// Register the decompressor for the data that was compressed using\r\n\t\t// `DEFLATE` compression algorithm (compression method `8`),\r\n\t\t// which is what `.xlsx` files use.\r\n\t\tunzip.register(USE_ZLIB_DECOMPRESSOR ? NativeZlibInflate : (USE_ASYNC_FFLATE_DECOMPRESSOR ? AsyncUnzipInflate : UnzipInflate))\r\n\r\n\t\tstream\r\n\t\t\t// Catch errors emitted from the input stream (for example, a file read error).\r\n\t\t\t.on('error', onError)\r\n\t\t\t// When another chunk of data is read from the input stream.\r\n\t\t\t.on('data', (chunk) => {\r\n\t\t\t\t// If there already was an error while reading this `.zip` file,\r\n\t\t\t\t// ignore any follow-up data chunks.\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t\t// Validate the `.zip` archive as its data comes through.\r\n\t\t\t\tvalidateChunk(chunk)\r\n\t\t\t\t// If the `.zip` archive is found to be invalid, stop any further\r\n\t\t\t\t// processing of it.\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t\t// Push the next data chunk to `fflate`'s `Unzip` class instance.\r\n\t\t\t\t//\r\n\t\t\t\t// The `.push()` function of `fflate`'s own `ZipInflate` decompressor is synchronous,\r\n\t\t\t\t// meaning that by the time it returns, any complete files entries encountered so far\r\n\t\t\t\t// have already been decompressed and populated in the `files` object.\r\n\t\t\t\t//\r\n\t\t\t\t// The `.push()` function of `NativeZlibInflate` decompressor is asynchronous,\r\n\t\t\t\t// so it requires hacking around with the counter of \"still being decompressed\" entries\r\n\t\t\t\t// in order to detect the actual finish of the archive's decompression process.\r\n\t\t\t\t//\r\n\t\t\t\ttry {\r\n\t\t\t\t\tunzip.push(chunk, false)\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tonError(error)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t// When there's no more data in the input stream to consume,\r\n\t\t\t// finish reading the `.zip` archive.\r\n\t\t\t.on('end', () => {\r\n\t\t\t\t// If there were any errors when reading the `.zip` archive,\r\n\t\t\t\t// don't `resolve()` with anything.\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\t\t\t\ttry {\r\n\t\t\t\t\t// Signal the end of the archive to `fflate`'s `Unzip` class instance.\r\n\t\t\t\t\t// It will flush any remaining state in it.\r\n\t\t\t\t\tunzip.push(new Uint8Array(0), true)\r\n\t\t\t\t\t// The input stream has ended.\r\n\t\t\t\t\tnoMoreEntries = true\r\n\t\t\t\t\t// The entries may still be decompressing asynchronously.\r\n\t\t\t\t\t// In that case, resolve once they all finish decompresssing.\r\n\t\t\t\t\t// Or, resolve if all entries have already finished decompressing by now.\r\n\t\t\t\t\tresolveIfDone()\r\n\t\t\t\t} catch (error) {\r\n\t\t\t\t\tonError(error)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t})\r\n}\r\n\r\n// Every section in a `.zip` archive is marked with 4 bytes, the first two of which\r\n// are `0x50` and `0x4B`, which reads \"PK\", referencing the initials of the inventor Phil Katz.\r\n//\r\n// It looks like `fflate`'s `Unzip` doesn't ever complain about whatever data is thrown at it.\r\n// Due to how `.zip` file format is defined, \"garbage\" data could be placed at various\r\n// places in it and it'd still be a valid `.zip` archive. It's likely that for this reason\r\n// `fflate` doesn't ever complain and simply emits no entries when fed any kind of invalid data.\r\n//\r\n// In order to introduce some basic validation, here we specifically demand\r\n// that a `.zip` archive must at least start with an individual file entry\r\n// because an `.xlsx` file creator softwared really shouldn't attempt doing\r\n// anything \"funny\" when writing a file, hence this adherence requirement.\r\n//\r\nfunction createZipFileValidator(onValidationResult) {\r\n\tconst firstBytesCount = 2\r\n\tconst firstBytes = []\r\n\tlet firstBytesCheckResult\r\n\treturn {\r\n\t\tvalidateChunk(chunk) {\r\n\t\t\tif (firstBytes.length < 2) {\r\n\t\t\t\tlet i = 0\r\n\t\t\t\twhile (i < chunk.length && i < firstBytesCount) {\r\n\t\t\t\t\tfirstBytes.push(chunk[i])\r\n\t\t\t\t\ti++\r\n\t\t\t\t}\r\n\t\t\t\tif (firstBytes.length === 2) {\r\n\t\t\t\t\tconst isValid = firstBytes[0] === 0x50 && firstBytes[1] === 0x4B\r\n\t\t\t\t\tonValidationResult(isValid)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// An implemenation of a `DEFLATE` decompressor for `fflate`'s `Unzip` class\r\n// that uses Node.js's \"native\" module `zlib`.\r\n//\r\n// It implements `fflate`'s decoder interface: `Unzip` constructs one decoder\r\n// per each entry, sets `ondata(error, chunk, isLast)` callback on it, and feeds it\r\n// the entry's compressed bytes by calling `push(chunk, isLast)` method.\r\n//\r\n// Unlike `fflate`'s synchronous `UnzipInflate` decoder, `zlib` decompresses asynchronously,\r\n// so an entry only finishes some \"ticks\" after its last chunk of its data is `push()`ed\r\n// by `fflate`'s `Unzip` class. To work around this issue, pending entries counter is used\r\n// to track when the archive really finishes unpacking.\r\n//\r\nclass NativeZlibInflate {\r\n\tstatic compression = 8\r\n\r\n\tconstructor() {\r\n\t\tthis.inflate = zlib.createInflateRaw()\r\n\t\tthis.inflate.on('data', (chunk) => this.ondata(null, chunk, false))\r\n\t\tthis.inflate.on('end', () => this.ondata(null, new Uint8Array(0), true))\r\n\t\tthis.inflate.on('error', (error) => this.ondata(error, null, false))\r\n\t}\r\n\r\n\tpush(chunk, isLast) {\r\n\t\tthis.inflate.write(Buffer.from(chunk))\r\n\t\tif (isLast) {\r\n\t\t\tthis.inflate.end()\r\n\t\t}\r\n\t}\r\n\r\n\tterminate() {\r\n\t\tthis.inflate.destroy()\r\n\t}\r\n}\r\n"],"mappings":";;;;;;AAgEA,IAAAA,OAAA,GAAAC,OAAA;AAGA,IAAAC,WAAA,GAAAD,OAAA;AACA,IAAAE,SAAA,GAAAC,sBAAA,CAAAH,OAAA;AAA4B,SAAAG,uBAAAC,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,gBAAAA,GAAA;AAAA,SAAAE,QAAAC,CAAA,sCAAAD,OAAA,wBAAAE,MAAA,uBAAAA,MAAA,CAAAC,QAAA,aAAAF,CAAA,kBAAAA,CAAA,gBAAAA,CAAA,WAAAA,CAAA,yBAAAC,MAAA,IAAAD,CAAA,CAAAG,WAAA,KAAAF,MAAA,IAAAD,CAAA,KAAAC,MAAA,CAAAG,SAAA,qBAAAJ,CAAA,KAAAD,OAAA,CAAAC,CAAA;AAAA,SAAAK,gBAAAC,QAAA,EAAAC,WAAA,UAAAD,QAAA,YAAAC,WAAA,eAAAC,SAAA;AAAA,SAAAC,kBAAAC,MAAA,EAAAC,KAAA,aAAAC,CAAA,MAAAA,CAAA,GAAAD,KAAA,CAAAE,MAAA,EAAAD,CAAA,UAAAE,UAAA,GAAAH,KAAA,CAAAC,CAAA,GAAAE,UAAA,CAAAC,UAAA,GAAAD,UAAA,CAAAC,UAAA,WAAAD,UAAA,CAAAE,YAAA,wBAAAF,UAAA,EAAAA,UAAA,CAAAG,QAAA,SAAAC,MAAA,CAAAC,cAAA,CAAAT,MAAA,EAAAU,cAAA,CAAAN,UAAA,CAAAO,GAAA,GAAAP,UAAA;AAAA,SAAAQ,aAAAf,WAAA,EAAAgB,UAAA,EAAAC,WAAA,QAAAD,UAAA,EAAAd,iBAAA,CAAAF,WAAA,CAAAH,SAAA,EAAAmB,UAAA,OAAAC,WAAA,EAAAf,iBAAA,CAAAF,WAAA,EAAAiB,WAAA,GAAAN,MAAA,CAAAC,cAAA,CAAAZ,WAAA,iBAAAU,QAAA,mBAAAV,WAAA;AAAA,SAAAkB,gBAAA5B,GAAA,EAAAwB,GAAA,EAAAK,KAAA,IAAAL,GAAA,GAAAD,cAAA,CAAAC,GAAA,OAAAA,GAAA,IAAAxB,GAAA,IAAAqB,MAAA,CAAAC,cAAA,CAAAtB,GAAA,EAAAwB,GAAA,IAAAK,KAAA,EAAAA,KAAA,EAAAX,UAAA,QAAAC,YAAA,QAAAC,QAAA,oBAAApB,GAAA,CAAAwB,GAAA,IAAAK,KAAA,WAAA7B,GAAA;AAAA,SAAAuB,eAAAO,GAAA,QAAAN,GAAA,GAAAO,YAAA,CAAAD,GAAA,oBAAA5B,OAAA,CAAAsB,GAAA,iBAAAA,GAAA,GAAAQ,MAAA,CAAAR,GAAA;AAAA,SAAAO,aAAAE,KAAA,EAAAC,IAAA,QAAAhC,OAAA,CAAA+B,KAAA,kBAAAA,KAAA,kBAAAA,KAAA,MAAAE,IAAA,GAAAF,KAAA,CAAA7B,MAAA,CAAAgC,WAAA,OAAAD,IAAA,KAAAE,SAAA,QAAAC,GAAA,GAAAH,IAAA,CAAAI,IAAA,CAAAN,KAAA,EAAAC,IAAA,oBAAAhC,OAAA,CAAAoC,GAAA,uBAAAA,GAAA,YAAA3B,SAAA,4DAAAuB,IAAA,gBAAAF,MAAA,GAAAQ,MAAA,EAAAP,KAAA,KApE5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAMQ,qBAAqB,GAAG,IAAI;;AAElC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAMC,6BAA6B,GAAG,KAAK;;AAE3C;AACA;AACA;AACA;AACA;AACe,SAASC,eAAeA,CAACC,MAAM,EAAmB;EAAA,IAAAC,IAAA,GAAAC,SAAA,CAAA9B,MAAA,QAAA8B,SAAA,QAAAT,SAAA,GAAAS,SAAA,MAAJ,CAAC,CAAC;IAAbC,MAAM,GAAAF,IAAA,CAANE,MAAM;EACvD;EACA,IAAMC,KAAK,GAAG,CAAC,CAAC;EAChB,IAAMC,WAAW,GAAG,CAAC,CAAC;EAEtB,IAAMC,MAAM,GAAG,SAATA,MAAMA,CAAIC,QAAQ,EAAK;IAC5B;IACA;IACA;IACA,IAAIJ,MAAM,IAAI,CAACA,MAAM,CAAC;MAAEK,IAAI,EAAED;IAAS,CAAC,CAAC,EAAE;MAC1C,OAAO,KAAK;IACb;IACAF,WAAW,CAACE,QAAQ,CAAC,GAAG,EAAE;EAC3B,CAAC;EAED,IAAME,UAAU,GAAG,SAAbA,UAAUA,CAAIF,QAAQ,EAAEG,KAAK,EAAK;IACvCL,WAAW,CAACE,QAAQ,CAAC,CAACI,IAAI,CAACD,KAAK,CAAC;EAClC,CAAC;EAED,IAAME,aAAa,GAAG,SAAhBA,aAAaA,CAAIL,QAAQ,EAAK;IACnCH,KAAK,CAACG,QAAQ,CAAC,GAAGM,kBAAM,CAACC,MAAM,CAACT,WAAW,CAACE,QAAQ,CAAC,CAAC;IACtD,OAAOF,WAAW,CAACE,QAAQ,CAAC;EAC7B,CAAC;EAED,OAAOQ,gBAAgB,CAACf,MAAM,EAAEM,MAAM,EAAEG,UAAU,EAAEG,aAAa,CAAC,CAACI,IAAI,CAAC,YAAM;IAC7E,OAAOZ,KAAK;EACb,CAAC,CAAC;AACH;AAEA,IAAMa,qBAAqB,GAAGxB,SAAS;AAEvC,SAASsB,gBAAgBA,CAACf,MAAM,EAAEM,MAAM,EAAEG,UAAU,EAAEG,aAAa,EAAE;EACpE,OAAO,IAAIM,OAAO,CAAC,UAACC,OAAO,EAAEC,MAAM,EAAK;IACvC,IAAIC,OAAO,GAAG,KAAK;IAEnB,IAAMC,OAAO,GAAG,SAAVA,OAAOA,CAAIC,KAAK,EAAK;MAC1B,IAAI,CAACF,OAAO,EAAE;QACbA,OAAO,GAAG,IAAI;QACdD,MAAM,CAACG,KAAK,CAAC;MACd;IACD,CAAC;;IAED;IACA;IACA;IACA;IACA;IACA,IAAIC,8BAA8B,GAAG,CAAC;IACtC,IAAIC,aAAa,GAAG,KAAK;IACzB,IAAMC,aAAa,GAAG,SAAhBA,aAAaA,CAAA,EAAS;MAC3B,IAAI,CAACL,OAAO,IAAII,aAAa,IAAID,8BAA8B,KAAK,CAAC,EAAE;QACtEL,OAAO,CAACF,qBAAqB,CAAC;MAC/B;IACD,CAAC;IAED,IAAAU,qBAAA,GAA0BC,sBAAsB,CAAC,UAACC,OAAO,EAAK;QAC7D,IAAI,CAACA,OAAO,EAAE;UACbP,OAAO,CAAC,IAAIQ,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC7C;MACD,CAAC,CAAC;MAJMC,aAAa,GAAAJ,qBAAA,CAAbI,aAAa;;IAMrB;IACA;IACA,IAAMC,KAAK,GAAG,IAAIC,aAAK,CAAC,UAACC,KAAK,EAAK;MAClC;MACA;MACA,IAAIb,OAAO,EAAE;QACZ;MACD;;MAEA;MACA;MACA,IAAIa,KAAK,CAACC,IAAI,CAACC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAC7B;MACD;MAEA,IAAI9B,MAAM,CAAC4B,KAAK,CAACC,IAAI,CAAC,KAAK,KAAK,EAAE;QACjC;MACD;MAEAX,8BAA8B,EAAE;;MAEhC;MACA;MACAU,KAAK,CAACG,MAAM,GAAG,UAACd,KAAK,EAAEb,KAAK,EAAE4B,MAAM,EAAK;QACxC,IAAIf,KAAK,EAAE;UACV,OAAOD,OAAO,CAACC,KAAK,CAAC;QACtB;QACAd,UAAU,CAACyB,KAAK,CAACC,IAAI,EAAEzB,KAAK,CAAC;QAC7B,IAAI4B,MAAM,EAAE;UACXd,8BAA8B,EAAE;UAChCZ,aAAa,CAACsB,KAAK,CAACC,IAAI,CAAC;UACzBT,aAAa,CAAC,CAAC;QAChB;MACD,CAAC;;MAED;MACAQ,KAAK,CAACK,KAAK,CAAC,CAAC;IACd,CAAC,CAAC;;IAEF;IACA;IACA;IACAP,KAAK,CAACQ,QAAQ,CAAC3C,qBAAqB,GAAG4C,iBAAiB,GAAI3C,6BAA6B,GAAG4C,iBAAiB,GAAGC,YAAa,CAAC;IAE9H3C;IACC;IAAA,CACC4C,EAAE,CAAC,OAAO,EAAEtB,OAAO;IACpB;IAAA,CACCsB,EAAE,CAAC,MAAM,EAAE,UAAClC,KAAK,EAAK;MACtB;MACA;MACA,IAAIW,OAAO,EAAE;QACZ;MACD;MACA;MACAU,aAAa,CAACrB,KAAK,CAAC;MACpB;MACA;MACA,IAAIW,OAAO,EAAE;QACZ;MACD;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,IAAI;QACHW,KAAK,CAACrB,IAAI,CAACD,KAAK,EAAE,KAAK,CAAC;MACzB,CAAC,CAAC,OAAOa,KAAK,EAAE;QACfD,OAAO,CAACC,KAAK,CAAC;MACf;IACD,CAAC;IACD;IACA;IAAA,CACCqB,EAAE,CAAC,KAAK,EAAE,YAAM;MAChB;MACA;MACA,IAAIvB,OAAO,EAAE;QACZ;MACD;MACA,IAAI;QACH;QACA;QACAW,KAAK,CAACrB,IAAI,CAAC,IAAIkC,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QACnC;QACApB,aAAa,GAAG,IAAI;QACpB;QACA;QACA;QACAC,aAAa,CAAC,CAAC;MAChB,CAAC,CAAC,OAAOH,KAAK,EAAE;QACfD,OAAO,CAACC,KAAK,CAAC;MACf;IACD,CAAC,CAAC;EACJ,CAAC,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASK,sBAAsBA,CAACkB,kBAAkB,EAAE;EACnD,IAAMC,eAAe,GAAG,CAAC;EACzB,IAAMC,UAAU,GAAG,EAAE;EACrB,IAAIC,qBAAqB;EACzB,OAAO;IACNlB,aAAa,WAAAA,cAACrB,KAAK,EAAE;MACpB,IAAIsC,UAAU,CAAC5E,MAAM,GAAG,CAAC,EAAE;QAC1B,IAAID,CAAC,GAAG,CAAC;QACT,OAAOA,CAAC,GAAGuC,KAAK,CAACtC,MAAM,IAAID,CAAC,GAAG4E,eAAe,EAAE;UAC/CC,UAAU,CAACrC,IAAI,CAACD,KAAK,CAACvC,CAAC,CAAC,CAAC;UACzBA,CAAC,EAAE;QACJ;QACA,IAAI6E,UAAU,CAAC5E,MAAM,KAAK,CAAC,EAAE;UAC5B,IAAMyD,OAAO,GAAGmB,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,IAAIA,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI;UAChEF,kBAAkB,CAACjB,OAAO,CAAC;QAC5B;MACD;IACD;EACD,CAAC;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA,IACMY,iBAAiB;EAGtB,SAAAA,kBAAA,EAAc;IAAA,IAAAS,KAAA;IAAAtF,eAAA,OAAA6E,iBAAA;IACb,IAAI,CAACU,OAAO,GAAGC,oBAAI,CAACC,gBAAgB,CAAC,CAAC;IACtC,IAAI,CAACF,OAAO,CAACP,EAAE,CAAC,MAAM,EAAE,UAAClC,KAAK;MAAA,OAAKwC,KAAI,CAACb,MAAM,CAAC,IAAI,EAAE3B,KAAK,EAAE,KAAK,CAAC;IAAA,EAAC;IACnE,IAAI,CAACyC,OAAO,CAACP,EAAE,CAAC,KAAK,EAAE;MAAA,OAAMM,KAAI,CAACb,MAAM,CAAC,IAAI,EAAE,IAAIQ,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;IAAA,EAAC;IACxE,IAAI,CAACM,OAAO,CAACP,EAAE,CAAC,OAAO,EAAE,UAACrB,KAAK;MAAA,OAAK2B,KAAI,CAACb,MAAM,CAACd,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC;IAAA,EAAC;EACrE;EAAC1C,YAAA,CAAA4D,iBAAA;IAAA7D,GAAA;IAAAK,KAAA,EAED,SAAA0B,KAAKD,KAAK,EAAE4B,MAAM,EAAE;MACnB,IAAI,CAACa,OAAO,CAACG,KAAK,CAACzC,kBAAM,CAAC0C,IAAI,CAAC7C,KAAK,CAAC,CAAC;MACtC,IAAI4B,MAAM,EAAE;QACX,IAAI,CAACa,OAAO,CAACK,GAAG,CAAC,CAAC;MACnB;IACD;EAAC;IAAA5E,GAAA;IAAAK,KAAA,EAED,SAAAwE,UAAA,EAAY;MACX,IAAI,CAACN,OAAO,CAACO,OAAO,CAAC,CAAC;IACvB;EAAC;EAAA,OAAAjB,iBAAA;AAAA;AAAAzD,eAAA,CAnBIyD,iBAAiB,iBACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unzipFromStream.js","names":["_unzipFromStreamUnzipper","_interopRequireDefault","require","obj","__esModule"],"sources":["../../source/zip/unzipFromStream.js"],"sourcesContent":["// Currently, there're two implementations:\r\n// * `fflate` — a pure-javascript implementation that uses `fflate` package.\r\n// * `unzipper` — a \"native\" Node.js module that uses Node's `zlib` which is written in C.\r\n//\r\n// The implementations are compared in a benchmark:\r\n//\r\n// ```\r\n// npm run test:benchmark:unzipFromStream\r\n// ```\r\n//\r\n// The benchmark tells that `unzipper` is 2x faster than `fflate`.\r\n//\r\nexport { default as default } from './unzipFromStream.unzipper.js'"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"unzipFromStream.js","names":["_unzipFromStreamUnzipper","_interopRequireDefault","require","obj","__esModule"],"sources":["../../source/zip/unzipFromStream.js"],"sourcesContent":["// `unzipFromStream` function reads `.zip` archive data from a Node.js stream.\r\n//\r\n// Even though it receives a Node.js stream as an input, it doesn't return the results\r\n// as a Node.js output stream (with `objectMode: true` setting). The reason is that\r\n// the result of this function is then passed to the XML parser which currently\r\n// doesn't support consuming a Node.js stream and instead consumes the entire XML document\r\n// as a single string. This means that implementing streaming output in this function\r\n// wouldn't result in any performance improvements, so currently it simply returns\r\n// a \"map\" of all files in the input `.zip` archive, and that seems to be enough.\r\n//\r\n// Currently, there're two decompressor implementations:\r\n// * `fflate` — a pure-javascript implementation that uses `fflate` package.\r\n// * `unzipper` — a \"native\" Node.js module that uses Node's `zlib` which is written in C.\r\n//\r\n// The implementations are compared in a benchmark:\r\n//\r\n// ```\r\n// npm run test:benchmark:unzipFromStream\r\n// ```\r\n//\r\n// The benchmark tells that `unzipper` is 2x faster than `fflate` with the default `ZipInflate` decompressor.\r\n//\r\n// However, when swapping `fflate`'s default `ZipInflate` decompressor with a custom\r\n// \"native\" `zlib` one, `fflate` happens to be about 20% faster than `unzipper`.\r\n//\r\n// Still, when measuring the total time of parsing `.xlsx` files,\r\n// the time difference becomes unmeasurable between `unzipper`\r\n// and `fflate` with \"native\" `zlib` decompressor,\r\n// as could be seen by running `npm run test:benchmark` command\r\n// where `fflate` is slightly faster than `unzipper`.\r\n//\r\n// * When decompressing a `1 MB` `.xlsx` file, the decompression time is `90 ms`\r\n// when using `fflate` with `zlib` decompressor and `100 ms` when using `unzipper` decompressor.\r\n// * When decompressing a `10 MB` `.xlsx` file, the decompression time is `530 ms`\r\n// when using `fflate` with `zlib` decompressor and `550 ms` when using `unzipper` decompressor.\r\n// * When decompressing a `50 MB` `.xlsx` file, the decompression time is `2800 ms`\r\n// when using `fflate` with `zlib` decompressor and `3000 ms` when using `unzipper` decompressor.\r\n//\r\n// So, at the end of the day, there's no substantial difference between the two\r\n// when it comes to parsing `.xlsx` files, and one may choose depending on personal preference.\r\n//\r\n// And my personal preference leans towards `unzipper` because:\r\n//\r\n// * I personally refactored it into `unzipper-esm` in about 5-6 hours.\r\n// https://github.com/ZJONSSON/node-unzipper/pull/356\r\n//\r\n// * It is designed as a Node.js-first module, i.e. it is designed around the concept\r\n// of Node.js streams \"from the ground up\". Meanwhile, `fflate` is a \"universal\" module\r\n// and it does not implement Node.js streams \"contract\", i.e. it just unzips the archive\r\n// as fast as it can consume it from the input stream, without throttling the data throughput\r\n// in cases when the input data flows faster than `fflate` can process it. This means that\r\n// in the \"worst case\" scenario when `fflate`'s decompressor is unable to keep up with the\r\n// data influx, it would \"buffer\" the entire `.zip` archive in RAM until it's processed.\r\n// And while this is no big deal by any means, it's still not as elegant as adhering to\r\n// Node.js streaming protocol.\r\n//\r\n// * `unzipper` uses native `zlib` decompressor which `fflate` doesn't officially include\r\n// and it had to be hacked into it using a couple of tricks. That's also no big deal,\r\n// but still a slightly weird experience.\r\n//\r\n// * Rumors are circulating that `fflate`'s \"streaming\" `Zip`/`Unzip` classes have a few\r\n// implementation issues when compared to non-\"streaming\" `zipSync`/`unzipSync`/`zip`/`unzip` functions.\r\n// Some people even suggested in the comments that `Zip`/`Unzip` classes are not really production-ready\r\n// when compared to `zipSync`/`unzipSync`/`zip`/`unzip` functions.\r\n// https://github.com/101arrowz/fflate/issues/282\r\n//\r\nexport { default as default } from './unzipFromStream.unzipper.js'"],"mappings":";;;;;;;;;;;AAkEA,IAAAA,wBAAA,GAAAC,sBAAA,CAAAC,OAAA;AAAkE,SAAAD,uBAAAE,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,gBAAAA,GAAA"}
|
|
@@ -6,25 +6,16 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports["default"] = unzipFromStream;
|
|
7
7
|
var _unzipperEsm = require("unzipper-esm");
|
|
8
8
|
var _buffer = require("buffer");
|
|
9
|
-
//
|
|
10
|
-
// This means that most likely it's more performant than an equivalent javascript-only implementation.
|
|
11
|
-
|
|
12
|
-
// `unzipper` has a bug — it is written in CommonJS and uses a conditional `require()` call
|
|
13
|
-
// to create an AWS S3 client instance: `require('@aws-sdk/client-s3')`.
|
|
14
|
-
// https://github.com/ZJONSSON/node-unzipper/issues/330
|
|
15
|
-
// The author of the package refuses to acknowledge the issue and apply a simple fix.
|
|
16
|
-
// The package, therefore, looks like an "abandonware".
|
|
17
|
-
// Someone could easily fix the issue though by forking the package.
|
|
9
|
+
// Considerations:
|
|
18
10
|
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
11
|
+
// * `unzipper` unpacks a `.zip` file using Node.js's "native" `zlib` module.
|
|
12
|
+
// This means that it's more performant than any equivalent pure-javascript decompressor.
|
|
21
13
|
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// result in errors when using other packages that happen to `import` anything from "@aws-sdk/client-s3" package,
|
|
25
|
-
// so it's not really a workaround but more of a ticking bomb. Not to mention that it introduces
|
|
26
|
-
// unnecessary complexity and "esoteric knowledge" to the application setup.
|
|
14
|
+
// * `unzipper` is a true "streaming" unpacker: it works in a "pull" fashion rather than a "push" one.
|
|
15
|
+
// New chunks of archived data are only read and decompressed as the receiver is ready to process them.
|
|
27
16
|
//
|
|
17
|
+
// * `unzipper` can completely skip a given compressed file entry if it's of no interest.
|
|
18
|
+
// This means that a `.zip` archive could be read in multiple passes without performance penalty.
|
|
28
19
|
|
|
29
20
|
/**
|
|
30
21
|
* Reads `*.zip` file contents.
|
|
@@ -36,6 +27,31 @@ function unzipFromStream(stream) {
|
|
|
36
27
|
filter = _ref.filter;
|
|
37
28
|
// The `files` object stores the files and their contents.
|
|
38
29
|
var files = {};
|
|
30
|
+
var filesChunks = {};
|
|
31
|
+
var onFile = function onFile(filePath) {
|
|
32
|
+
// See if this file should be ignored.
|
|
33
|
+
// If it should, this entry won't be processed, i.e. `Unzip` will not try
|
|
34
|
+
// to decompress its data, and will just discard it.
|
|
35
|
+
if (filter && !filter({
|
|
36
|
+
path: filePath
|
|
37
|
+
})) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
filesChunks[filePath] = [];
|
|
41
|
+
};
|
|
42
|
+
var onFileData = function onFileData(filePath, chunk) {
|
|
43
|
+
filesChunks[filePath].push(chunk);
|
|
44
|
+
};
|
|
45
|
+
var onFileDataEnd = function onFileDataEnd(filePath) {
|
|
46
|
+
files[filePath] = _buffer.Buffer.concat(filesChunks[filePath]);
|
|
47
|
+
delete filesChunks[filePath];
|
|
48
|
+
};
|
|
49
|
+
return unzipFromStream_(stream, onFile, onFileData, onFileDataEnd).then(function () {
|
|
50
|
+
return files;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
var PROMISE_RESOLVE_VALUE = undefined;
|
|
54
|
+
function unzipFromStream_(stream, onFile, onFileData, onFileDataEnd) {
|
|
39
55
|
return new Promise(function (resolve, reject) {
|
|
40
56
|
var promises = [];
|
|
41
57
|
var errored = false;
|
|
@@ -76,7 +92,7 @@ function unzipFromStream(stream) {
|
|
|
76
92
|
// but I didn't remove it just to potentially prevent any potential silly bugs
|
|
77
93
|
// in case of some potential changes in some potential future.
|
|
78
94
|
Promise.all(promises).then(function () {
|
|
79
|
-
resolve(
|
|
95
|
+
resolve(PROMISE_RESOLVE_VALUE);
|
|
80
96
|
}, onError);
|
|
81
97
|
}
|
|
82
98
|
}).on('entry', function (entry) {
|
|
@@ -90,12 +106,8 @@ function unzipFromStream(stream) {
|
|
|
90
106
|
if (errored) {
|
|
91
107
|
ignore = true;
|
|
92
108
|
}
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
path: entry.path
|
|
96
|
-
})) {
|
|
97
|
-
ignore = true;
|
|
98
|
-
}
|
|
109
|
+
if (onFile(entry.path) === false) {
|
|
110
|
+
ignore = true;
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
// If this file should be ignored.
|
|
@@ -106,18 +118,17 @@ function unzipFromStream(stream) {
|
|
|
106
118
|
entry.autodrain().on('error', onError);
|
|
107
119
|
return;
|
|
108
120
|
}
|
|
109
|
-
var chunks = [];
|
|
110
121
|
promises.push(new Promise(function (resolve) {
|
|
111
122
|
// `entry` seems to be a generic Node.js stream.
|
|
112
123
|
// `entry.pipe()` pipes the file contents to a stream.
|
|
113
124
|
// `entry.stream()` returns a readable stream.
|
|
114
125
|
// `entry.buffer()` returns a promise that resolves to a `Buffer` with the file contents.
|
|
115
126
|
entry.on('data', function (data) {
|
|
116
|
-
|
|
127
|
+
onFileData(entry.path, data);
|
|
117
128
|
}).on('error', function (error) {
|
|
118
129
|
onError(error);
|
|
119
130
|
}).on('finish', function () {
|
|
120
|
-
|
|
131
|
+
onFileDataEnd(entry.path);
|
|
121
132
|
resolve();
|
|
122
133
|
});
|
|
123
134
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unzipFromStream.unzipper.js","names":["_unzipperEsm","require","_buffer","unzipFromStream","stream","_ref","arguments","length","undefined","filter","files","
|
|
1
|
+
{"version":3,"file":"unzipFromStream.unzipper.js","names":["_unzipperEsm","require","_buffer","unzipFromStream","stream","_ref","arguments","length","undefined","filter","files","filesChunks","onFile","filePath","path","onFileData","chunk","push","onFileDataEnd","Buffer","concat","unzipFromStream_","then","PROMISE_RESOLVE_VALUE","Promise","resolve","reject","promises","errored","onError","error","on","pipe","Parse","all","entry","ignore","type","autodrain","data"],"sources":["../../source/zip/unzipFromStream.unzipper.js"],"sourcesContent":["// Considerations:\r\n//\r\n// * `unzipper` unpacks a `.zip` file using Node.js's \"native\" `zlib` module.\r\n// This means that it's more performant than any equivalent pure-javascript decompressor.\r\n//\r\n// * `unzipper` is a true \"streaming\" unpacker: it works in a \"pull\" fashion rather than a \"push\" one.\r\n// New chunks of archived data are only read and decompressed as the receiver is ready to process them.\r\n//\r\n// * `unzipper` can completely skip a given compressed file entry if it's of no interest.\r\n// This means that a `.zip` archive could be read in multiple passes without performance penalty.\r\n\r\nimport { Parse } from 'unzipper-esm'\r\n\r\nimport { Buffer } from 'buffer'\r\n\r\n/**\r\n * Reads `*.zip` file contents.\r\n * @param {Stream} stream\r\n * @return {Promise<Record<string,Buffer>>} Resolves to an object holding `*.zip` file entries. P.S. `Buffer` is a `Uint8Array`.\r\n */\r\nexport default function unzipFromStream(stream, { filter } = {}) {\r\n\t// The `files` object stores the files and their contents.\r\n\tconst files = {}\r\n\tconst filesChunks = {}\r\n\r\n\tconst onFile = (filePath) => {\r\n\t\t// See if this file should be ignored.\r\n\t\t// If it should, this entry won't be processed, i.e. `Unzip` will not try\r\n\t\t// to decompress its data, and will just discard it.\r\n\t\tif (filter && !filter({ path: filePath })) {\r\n\t\t\treturn false\r\n\t\t}\r\n\t\tfilesChunks[filePath] = []\r\n\t}\r\n\r\n\tconst onFileData = (filePath, chunk) => {\r\n\t\tfilesChunks[filePath].push(chunk)\r\n\t}\r\n\r\n\tconst onFileDataEnd = (filePath) => {\r\n\t\tfiles[filePath] = Buffer.concat(filesChunks[filePath])\r\n\t\tdelete filesChunks[filePath]\r\n\t}\r\n\r\n\treturn unzipFromStream_(stream, onFile, onFileData, onFileDataEnd).then(() => {\r\n\t\treturn files\r\n\t})\r\n}\r\n\r\nconst PROMISE_RESOLVE_VALUE = undefined\r\n\r\nfunction unzipFromStream_(stream, onFile, onFileData, onFileDataEnd) {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tconst promises = []\r\n\r\n\t\tlet errored = false\r\n\r\n\t\tconst onError = (error) => {\r\n\t\t\tif (!errored) {\r\n\t\t\t\terrored = true\r\n\t\t\t\treject(error)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstream\r\n\t\t\t// This first \"error\" listener catches the original stream errors.\r\n\t\t\t//\r\n\t\t\t// That's because the .pipe() method does not automatically propagate errors\r\n\t\t\t// from a source (input) stream to the destination stream or the end of the pipeline.\r\n\t\t\t// You would need to attach an 'error' event handler to each stream in the chain.\r\n\t\t\t//\r\n\t\t\t// A more convenient alternative would be to use `stream.pipeline()` function:\r\n\t\t\t// `pipeline(stream1, stream2, (error) => { ... })`\r\n\t\t\t//\r\n\t\t\t.on('error', onError)\r\n\t\t\t// Pipe the input stream through the unzipper stream.\r\n\t\t\t.pipe(Parse())\r\n\t\t\t// This second \"error\" listener catches the unzipper stream errors.\r\n\t\t\t//\r\n\t\t\t// That's because the .pipe() method does not automatically propagate errors\r\n\t\t\t// from a source (input) stream to the destination stream or the end of the pipeline.\r\n\t\t\t// You would need to attach an 'error' event handler to each stream in the chain.\r\n\t\t\t//\r\n\t\t\t// A more convenient alternative would be to use `stream.pipeline()` function:\r\n\t\t\t// `pipeline(stream1, stream2, (error) => { ... })`\r\n\t\t\t//\r\n\t\t\t.on('error', onError)\r\n\t\t\t// The unzipper stream is closed when all `entries` have been reported.\r\n\t\t\t.on('finish', () => {\r\n\t\t\t\tif (!errored) {\r\n\t\t\t\t\t// Wait for all `entries` to be read.\r\n\t\t\t\t\t// The second argument of `.then()` function is not required\r\n\t\t\t\t\t// but I didn't remove it just to potentially prevent any potential silly bugs\r\n\t\t\t\t\t// in case of some potential changes in some potential future.\r\n\t\t\t\t\tPromise.all(promises).then(() => {\r\n\t\t\t\t\t\tresolve(PROMISE_RESOLVE_VALUE)\r\n\t\t\t\t\t}, onError)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\t.on('entry', (entry) => {\r\n\t\t\t\t// See if this file should be ignored.\r\n\t\t\t\tlet ignore = false\r\n\t\t\t\t// `entry.type` could be 'Directory' or 'File'.\r\n\t\t\t\t// Ignore anything except files.\r\n\t\t\t\tif (entry.type === 'Directory') {\r\n\t\t\t\t\tignore = true\r\n\t\t\t\t}\r\n\t\t\t\tif (errored) {\r\n\t\t\t\t\tignore = true\r\n\t\t\t\t}\r\n\t\t\t\tif (onFile(entry.path) === false) {\r\n\t\t\t\t\tignore = true\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// If this file should be ignored.\r\n\t\t\t\tif (ignore) {\r\n\t\t\t\t\t// Call `entry.autodrain()` when you do not intend to process a specific `entry`'s raw data.\r\n\t\t\t\t\t// Otherwise, if an `entry` is not consumed (via .pipe(), .buffer(), or .autodrain()),\r\n\t\t\t\t\t// the stream will halt, preventing further file processing.\r\n\t\t\t\t\tentry.autodrain().on('error', onError)\r\n\t\t\t\t\treturn\r\n\t\t\t\t}\r\n\r\n\t\t\t\tpromises.push(new Promise((resolve) => {\r\n\t\t\t\t\t// `entry` seems to be a generic Node.js stream.\r\n\t\t\t\t\t// `entry.pipe()` pipes the file contents to a stream.\r\n\t\t\t\t\t// `entry.stream()` returns a readable stream.\r\n\t\t\t\t\t// `entry.buffer()` returns a promise that resolves to a `Buffer` with the file contents.\r\n\t\t\t\t\tentry\r\n\t\t\t\t\t\t.on('data', (data) => {\r\n\t\t\t\t\t\t\tonFileData(entry.path, data)\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\t.on('error', (error) => {\r\n\t\t\t\t\t\t\tonError(error)\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\t.on('finish', () => {\r\n\t\t\t\t\t\t\tonFileDataEnd(entry.path)\r\n\t\t\t\t\t\t\tresolve()\r\n\t\t\t\t\t\t})\r\n\t\t\t\t}))\r\n\t\t\t})\r\n\t})\r\n}"],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { strFromU8 } from 'fflate';
|
|
2
|
+
import checkpoint from '../utility/checkpoint.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* @param {Record<string,Uint8Array} entries
|
|
5
6
|
* @returns {Record<string,string>}
|
|
6
7
|
*/
|
|
7
8
|
export default function convertValuesFromUint8ArraysToStrings(entries) {
|
|
9
|
+
checkpoint('convert files to strings');
|
|
8
10
|
var convertedEntries = {};
|
|
9
11
|
for (var _i = 0, _Object$keys = Object.keys(entries); _i < _Object$keys.length; _i++) {
|
|
10
12
|
var key = _Object$keys[_i];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertValuesFromUint8ArraysToStrings.js","names":["strFromU8","convertValuesFromUint8ArraysToStrings","entries","convertedEntries","_i","_Object$keys","Object","keys","length","key"],"sources":["../../source/export/convertValuesFromUint8ArraysToStrings.js"],"sourcesContent":["import { strFromU8 } from 'fflate'\r\n\r\n/**\r\n * @param {Record<string,Uint8Array} entries\r\n * @returns {Record<string,string>}\r\n */\r\nexport default function convertValuesFromUint8ArraysToStrings(entries) {\r\n\tconst convertedEntries = {}\r\n\tfor (const key of Object.keys(entries)) {\r\n\t\tconvertedEntries[key] = strFromU8(entries[key])\r\n\t}\r\n\treturn convertedEntries\r\n}"],"mappings":"AAAA,SAASA,SAAS,QAAQ,QAAQ;;
|
|
1
|
+
{"version":3,"file":"convertValuesFromUint8ArraysToStrings.js","names":["strFromU8","checkpoint","convertValuesFromUint8ArraysToStrings","entries","convertedEntries","_i","_Object$keys","Object","keys","length","key"],"sources":["../../source/export/convertValuesFromUint8ArraysToStrings.js"],"sourcesContent":["import { strFromU8 } from 'fflate'\r\n\r\nimport checkpoint from '../utility/checkpoint.js'\r\n\r\n/**\r\n * @param {Record<string,Uint8Array} entries\r\n * @returns {Record<string,string>}\r\n */\r\nexport default function convertValuesFromUint8ArraysToStrings(entries) {\r\n\tcheckpoint('convert files to strings')\r\n\tconst convertedEntries = {}\r\n\tfor (const key of Object.keys(entries)) {\r\n\t\tconvertedEntries[key] = strFromU8(entries[key])\r\n\t}\r\n\treturn convertedEntries\r\n}"],"mappings":"AAAA,SAASA,SAAS,QAAQ,QAAQ;AAElC,OAAOC,UAAU,MAAM,0BAA0B;;AAEjD;AACA;AACA;AACA;AACA,eAAe,SAASC,qCAAqCA,CAACC,OAAO,EAAE;EACtEF,UAAU,CAAC,0BAA0B,CAAC;EACtC,IAAMG,gBAAgB,GAAG,CAAC,CAAC;EAC3B,SAAAC,EAAA,MAAAC,YAAA,GAAkBC,MAAM,CAACC,IAAI,CAACL,OAAO,CAAC,EAAAE,EAAA,GAAAC,YAAA,CAAAG,MAAA,EAAAJ,EAAA,IAAE;IAAnC,IAAMK,GAAG,GAAAJ,YAAA,CAAAD,EAAA;IACbD,gBAAgB,CAACM,GAAG,CAAC,GAAGV,SAAS,CAACG,OAAO,CAACO,GAAG,CAAC,CAAC;EAChD;EACA,OAAON,gBAAgB;AACxB"}
|
|
@@ -9,19 +9,22 @@ import parseSheetData from '../parseSheetData/parseSheetData.js';
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Reads data from a single sheet of an `.xlsx` file as an array of rows (which are arrays of cells) or as an array of objects (if `options.schema` was passed).
|
|
12
|
+
* @param {function} [createWorkerFunction] — Creates a worker function.
|
|
13
|
+
* @param {function} parseXmlStream — SAX XML parser.
|
|
12
14
|
* @param {Record<string,string>} contents - A map of `.xml` files inside the `.xlsx` file (which itself is just a zipped directory).
|
|
13
|
-
* @param {object} xml — An object having a single property — `createDocument(string)` function.
|
|
14
15
|
* @param {string|number} [sheet] — Sheet name or number.
|
|
15
16
|
* @param {object} [options]
|
|
16
|
-
* @return {
|
|
17
|
+
* @return {Promise<SheetData>}
|
|
17
18
|
*/
|
|
18
|
-
export default function parseSheet(
|
|
19
|
-
|
|
19
|
+
export default function parseSheet(createWorkerFunction, parseXmlStream, contents, sheet, options) {
|
|
20
|
+
return parseSpreadsheetContents(createWorkerFunction, parseXmlStream, contents, _objectSpread(_objectSpread({}, options), {}, {
|
|
20
21
|
sheets: [sheet === undefined ? 1 : sheet]
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
})).then(function (sheets) {
|
|
23
|
+
var sheetData = sheets[0].data;
|
|
24
|
+
if (options && options.schema) {
|
|
25
|
+
return parseSheetData(sheetData, options.schema);
|
|
26
|
+
}
|
|
27
|
+
return sheetData;
|
|
28
|
+
});
|
|
26
29
|
}
|
|
27
30
|
//# sourceMappingURL=parseSheet.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseSheet.js","names":["parseSpreadsheetContents","parseSheetData","parseSheet","
|
|
1
|
+
{"version":3,"file":"parseSheet.js","names":["parseSpreadsheetContents","parseSheetData","parseSheet","createWorkerFunction","parseXmlStream","contents","sheet","options","_objectSpread","sheets","undefined","then","sheetData","data","schema"],"sources":["../../source/export/parseSheet.js"],"sourcesContent":["import parseSpreadsheetContents from '../xlsx/parseSpreadsheetContents.js'\r\nimport parseSheetData from '../parseSheetData/parseSheetData.js'\r\n\r\n/**\r\n * Reads data from a single sheet of an `.xlsx` file as an array of rows (which are arrays of cells) or as an array of objects (if `options.schema` was passed).\r\n * @param {function} [createWorkerFunction] — Creates a worker function.\r\n * @param {function} parseXmlStream — SAX XML parser.\r\n * @param {Record<string,string>} contents - A map of `.xml` files inside the `.xlsx` file (which itself is just a zipped directory).\r\n * @param {string|number} [sheet] — Sheet name or number.\r\n * @param {object} [options]\r\n * @return {Promise<SheetData>}\r\n */\r\nexport default function parseSheet(createWorkerFunction, parseXmlStream, contents, sheet, options) {\r\n\treturn parseSpreadsheetContents(createWorkerFunction, parseXmlStream, contents, {\r\n\t\t...options,\r\n\t\tsheets: [sheet === undefined ? 1 : sheet],\r\n\t}).then((sheets) => {\r\n\t\tconst sheetData = sheets[0].data\r\n\t\tif (options && options.schema) {\r\n\t\t\treturn parseSheetData(sheetData, options.schema)\r\n\t\t}\r\n\t\treturn sheetData\r\n\t})\r\n}"],"mappings":";;;;;;AAAA,OAAOA,wBAAwB,MAAM,qCAAqC;AAC1E,OAAOC,cAAc,MAAM,qCAAqC;;AAEhE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,SAASC,UAAUA,CAACC,oBAAoB,EAAEC,cAAc,EAAEC,QAAQ,EAAEC,KAAK,EAAEC,OAAO,EAAE;EAClG,OAAOP,wBAAwB,CAACG,oBAAoB,EAAEC,cAAc,EAAEC,QAAQ,EAAAG,aAAA,CAAAA,aAAA,KAC1ED,OAAO;IACVE,MAAM,EAAE,CAACH,KAAK,KAAKI,SAAS,GAAG,CAAC,GAAGJ,KAAK;EAAC,EACzC,CAAC,CAACK,IAAI,CAAC,UAACF,MAAM,EAAK;IACnB,IAAMG,SAAS,GAAGH,MAAM,CAAC,CAAC,CAAC,CAACI,IAAI;IAChC,IAAIN,OAAO,IAAIA,OAAO,CAACO,MAAM,EAAE;MAC9B,OAAOb,cAAc,CAACW,SAAS,EAAEL,OAAO,CAACO,MAAM,CAAC;IACjD;IACA,OAAOF,SAAS;EACjB,CAAC,CAAC;AACH"}
|