read-excel-file 9.1.1 → 9.3.0
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 +14 -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 +338 -0
- package/commonjs/zip/unzipFromStream.fflate.js.map +1 -0
- package/commonjs/zip/unzipFromStream.js +8 -200
- package/commonjs/zip/unzipFromStream.js.map +1 -1
- package/commonjs/zip/unzipFromStream.unzipper.js +138 -0
- package/commonjs/zip/unzipFromStream.unzipper.js.map +1 -0
- 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 +336 -0
- package/modules/zip/unzipFromStream.fflate.js.map +1 -0
- package/modules/zip/unzipFromStream.js +55 -187
- package/modules/zip/unzipFromStream.js.map +1 -1
- package/modules/zip/unzipFromStream.unzipper.js +133 -0
- package/modules/zip/unzipFromStream.unzipper.js.map +1 -0
- package/package.json +12 -32
- 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
|
@@ -1,200 +1,68 @@
|
|
|
1
|
-
//
|
|
2
|
-
// https://github.com/catamphetamine/read-excel-file/pull/122
|
|
3
|
-
|
|
4
|
-
// A `*.zip` file consists of individual file entries with the "total" summary section
|
|
5
|
-
// placed at the end of the file rather than at the start of it, which was originally done
|
|
6
|
-
// to allow for easy append of data to a given `.zip` file.
|
|
7
|
-
// https://en.wikipedia.org/wiki/ZIP_(file_format)
|
|
1
|
+
// `unzipFromStream` function reads `.zip` archive data from a Node.js stream.
|
|
8
2
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
3
|
+
// Even though it receives a Node.js stream as an input, it doesn't return the results
|
|
4
|
+
// as a Node.js output stream (with `objectMode: true` setting). The reason is that
|
|
5
|
+
// the result of this function is then passed to the XML parser which currently
|
|
6
|
+
// doesn't support consuming a Node.js stream and instead consumes the entire XML document
|
|
7
|
+
// as a single string. This means that implementing streaming output in this function
|
|
8
|
+
// wouldn't result in any performance improvements, so currently it simply returns
|
|
9
|
+
// a "map" of all files in the input `.zip` archive, and that seems to be enough.
|
|
12
10
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
// for individual file entries and handle them one-by-one as they come.
|
|
11
|
+
// Currently, there're two decompressor implementations:
|
|
12
|
+
// * `fflate` — a pure-javascript implementation that uses `fflate` package.
|
|
13
|
+
// * `unzipper` — a "native" Node.js module that uses Node's `zlib` which is written in C.
|
|
17
14
|
//
|
|
18
|
-
//
|
|
19
|
-
// because an `*.xlsx` files is supposed to be a normal `.zip` archive
|
|
20
|
-
// without any "trickery" such as "deleted" files or "garbage" data
|
|
21
|
-
// hiding under the hood.
|
|
15
|
+
// The implementations are compared in a benchmark:
|
|
22
16
|
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
17
|
+
// ```
|
|
18
|
+
// npm run test:benchmark:unzipFromStream
|
|
19
|
+
// ```
|
|
25
20
|
//
|
|
26
|
-
//
|
|
21
|
+
// The benchmark tells that `unzipper` is 2x faster than `fflate` with the default `ZipInflate` decompressor.
|
|
27
22
|
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
// that was previously compressed using `DEFLATE` compressing algorithm,
|
|
31
|
-
// which is what `*.xlsx` files use.
|
|
23
|
+
// However, when swapping `fflate`'s default `ZipInflate` decompressor with a custom
|
|
24
|
+
// "native" `zlib` one, `fflate` happens to be about 20% faster than `unzipper`.
|
|
32
25
|
//
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
// and then collects the decompressed file entries.
|
|
26
|
+
// Still, when measuring the total time of parsing `.xlsx` files,
|
|
27
|
+
// the time difference becomes unmeasurable between `unzipper`
|
|
28
|
+
// and `fflate` with "native" `zlib` decompressor,
|
|
29
|
+
// as could be seen by running `npm run test:benchmark` command
|
|
30
|
+
// where `fflate` is slightly faster than `unzipper`.
|
|
39
31
|
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
32
|
+
// * When decompressing a `1 MB` `.xlsx` file, the decompression time is `90 ms`
|
|
33
|
+
// when using `fflate` with `zlib` decompressor and `100 ms` when using `unzipper` decompressor.
|
|
34
|
+
// * When decompressing a `10 MB` `.xlsx` file, the decompression time is `530 ms`
|
|
35
|
+
// when using `fflate` with `zlib` decompressor and `550 ms` when using `unzipper` decompressor.
|
|
36
|
+
// * When decompressing a `50 MB` `.xlsx` file, the decompression time is `2800 ms`
|
|
37
|
+
// when using `fflate` with `zlib` decompressor and `3000 ms` when using `unzipper` decompressor.
|
|
45
38
|
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Reads `*.zip` file contents.
|
|
51
|
-
* @param {Stream} stream
|
|
52
|
-
* @return {Promise<Record<string,Buffer>>} Resolves to an object holding `*.zip` file entries. P.S. `Buffer` is a `Uint8Array`.
|
|
53
|
-
*/
|
|
54
|
-
export default function unzipFromStream(stream) {
|
|
55
|
-
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
56
|
-
filter = _ref.filter;
|
|
57
|
-
// The `files` object stores the files and their contents.
|
|
58
|
-
var files = {};
|
|
59
|
-
return new Promise(function (resolve, reject) {
|
|
60
|
-
var errored = false;
|
|
61
|
-
var onError = function onError(error) {
|
|
62
|
-
if (!errored) {
|
|
63
|
-
errored = true;
|
|
64
|
-
reject(error);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
var _createZipFileValidat = createZipFileValidator(function (isValid) {
|
|
68
|
-
if (!isValid) {
|
|
69
|
-
onError(new Error('Invalid `.zip` archive'));
|
|
70
|
-
}
|
|
71
|
-
}),
|
|
72
|
-
validateChunk = _createZipFileValidat.validateChunk;
|
|
73
|
-
|
|
74
|
-
// `Unzip` discovers each individual file entry in the input data stream
|
|
75
|
-
// and then calls the callback function for each such entry.
|
|
76
|
-
var unzip = new Unzip(function (entry) {
|
|
77
|
-
// If there already was an error while reading this `.zip` file,
|
|
78
|
-
// ignore any follow-up entries.
|
|
79
|
-
if (errored) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Skip directory entries (their names end with a slash).
|
|
84
|
-
// Only files are of any interest.
|
|
85
|
-
if (entry.name.endsWith('/')) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// See if this file should be ignored.
|
|
90
|
-
// If it should, this entry won't be processed, i.e. `Unzip` will not try
|
|
91
|
-
// to decompress its data, and will just discard it.
|
|
92
|
-
if (filter && !filter({
|
|
93
|
-
path: entry.name
|
|
94
|
-
})) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
var chunks = [];
|
|
98
|
-
|
|
99
|
-
// `entry.ondata` is called with each decompressed chunk of the entry,
|
|
100
|
-
// and a final time with `isLast === true` once the entry is complete.
|
|
101
|
-
entry.ondata = function (error, chunk, isLast) {
|
|
102
|
-
if (error) {
|
|
103
|
-
return onError(error);
|
|
104
|
-
}
|
|
105
|
-
chunks.push(chunk);
|
|
106
|
-
if (isLast) {
|
|
107
|
-
files[entry.name] = Buffer.concat(chunks);
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// Start decompressing this entry.
|
|
112
|
-
entry.start();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Register the decompressor for the data that was compressed using
|
|
116
|
-
// `DEFLATE` compression algorithm (compression method `8`),
|
|
117
|
-
// which is what `.xlsx` files use.
|
|
118
|
-
unzip.register(UnzipInflate);
|
|
119
|
-
stream
|
|
120
|
-
// Catch errors emitted from the input stream (for example, a file read error).
|
|
121
|
-
.on('error', onError)
|
|
122
|
-
// When another chunk of data is read from the input stream.
|
|
123
|
-
.on('data', function (chunk) {
|
|
124
|
-
// If there already was an error while reading this `.zip` file,
|
|
125
|
-
// ignore any follow-up data chunks.
|
|
126
|
-
if (errored) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
// Validate the `.zip` archive as its data comes through.
|
|
130
|
-
validateChunk(chunk);
|
|
131
|
-
// If the `.zip` archive is found to be invalid, stop any further
|
|
132
|
-
// processing of it.
|
|
133
|
-
if (errored) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
// Push the next data chunk to `fflate`'s `Unzip` class instance.
|
|
137
|
-
// The `.push()` function is synchronous, meaning that by the time it returns,
|
|
138
|
-
// any complete files entries encountered so far have already been decompressed
|
|
139
|
-
// and populated in the `files` object.
|
|
140
|
-
try {
|
|
141
|
-
unzip.push(chunk, false);
|
|
142
|
-
} catch (error) {
|
|
143
|
-
onError(error);
|
|
144
|
-
}
|
|
145
|
-
})
|
|
146
|
-
// When there's no more data in the input stream to consume,
|
|
147
|
-
// finish reading the `.zip` archive.
|
|
148
|
-
.on('end', function () {
|
|
149
|
-
// If there were any errors when reading the `.zip` archive,
|
|
150
|
-
// don't `resolve()` with anything.
|
|
151
|
-
if (errored) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
try {
|
|
155
|
-
// Signal the end of the archive to `fflate`'s `Unzip` class instance.
|
|
156
|
-
// It will flush any remaining state in it.
|
|
157
|
-
unzip.push(new Uint8Array(0), true);
|
|
158
|
-
// Resolve with the unzipped files.
|
|
159
|
-
resolve(files);
|
|
160
|
-
} catch (error) {
|
|
161
|
-
onError(error);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Every section in a `.zip` archive is marked with 4 bytes, the first two of which
|
|
168
|
-
// are `0x50` and `0x4B`, which reads "PK", referencing the initials of the inventor Phil Katz.
|
|
39
|
+
// So, at the end of the day, there's no substantial difference between the two
|
|
40
|
+
// when it comes to parsing `.xlsx` files, and one may choose depending on personal preference.
|
|
169
41
|
//
|
|
170
|
-
//
|
|
171
|
-
// Due to how `.zip` file format is defined, "garbage" data could be placed at various
|
|
172
|
-
// places in it and it'd still be a valid `.zip` archive. It's likely that for this reason
|
|
173
|
-
// `fflate` doesn't ever complain and simply emits no entries when fed any kind of invalid data.
|
|
42
|
+
// And my personal preference leans towards `unzipper` because:
|
|
174
43
|
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
// because an `.xlsx` file creator softwared really shouldn't attempt doing
|
|
178
|
-
// anything "funny" when writing a file, hence this adherence requirement.
|
|
44
|
+
// * I personally refactored it into `unzipper-esm` in about 5-6 hours.
|
|
45
|
+
// https://github.com/ZJONSSON/node-unzipper/pull/356
|
|
179
46
|
//
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
47
|
+
// * It is designed as a Node.js-first module, i.e. it is designed around the concept
|
|
48
|
+
// of Node.js streams "from the ground up". Meanwhile, `fflate` is a "universal" module
|
|
49
|
+
// and it does not implement Node.js streams "contract", i.e. it just unzips the archive
|
|
50
|
+
// as fast as it can consume it from the input stream, without throttling the data throughput
|
|
51
|
+
// in cases when the input data flows faster than `fflate` can process it. This means that
|
|
52
|
+
// in the "worst case" scenario when `fflate`'s decompressor is unable to keep up with the
|
|
53
|
+
// data influx, it would "buffer" the entire `.zip` archive in RAM until it's processed.
|
|
54
|
+
// And while this is no big deal by any means, it's still not as elegant as adhering to
|
|
55
|
+
// Node.js streaming protocol.
|
|
56
|
+
//
|
|
57
|
+
// * `unzipper` uses native `zlib` decompressor which `fflate` doesn't officially include
|
|
58
|
+
// and it had to be hacked into it using a couple of tricks. That's also no big deal,
|
|
59
|
+
// but still a slightly weird experience.
|
|
60
|
+
//
|
|
61
|
+
// * Rumors are circulating that `fflate`'s "streaming" `Zip`/`Unzip` classes have a few
|
|
62
|
+
// implementation issues when compared to non-"streaming" `zipSync`/`unzipSync`/`zip`/`unzip` functions.
|
|
63
|
+
// Some people even suggested in the comments that `Zip`/`Unzip` classes are not really production-ready
|
|
64
|
+
// when compared to `zipSync`/`unzipSync`/`zip`/`unzip` functions.
|
|
65
|
+
// https://github.com/101arrowz/fflate/issues/282
|
|
66
|
+
//
|
|
67
|
+
export { default } from './unzipFromStream.unzipper.js';
|
|
200
68
|
//# sourceMappingURL=unzipFromStream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unzipFromStream.js","names":["Unzip","UnzipInflate","Buffer","unzipFromStream","stream","_ref","arguments","length","undefined","filter","files","Promise","resolve","reject","errored","onError","error","_createZipFileValidat","createZipFileValidator","isValid","Error","validateChunk","unzip","entry","name","endsWith","path","chunks","ondata","chunk","isLast","push","concat","start","register","on","Uint8Array","onValidationResult","firstBytesCount","firstBytes","firstBytesCheckResult","i"],"sources":["../../source/zip/unzipFromStream.js"],"sourcesContent":["// 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.js","names":["default"],"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":"AAAA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,OAAkB,QAAQ,+BAA+B"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Considerations:
|
|
2
|
+
//
|
|
3
|
+
// * `unzipper` unpacks a `.zip` file using Node.js's "native" `zlib` module.
|
|
4
|
+
// This means that it's more performant than any equivalent pure-javascript decompressor.
|
|
5
|
+
//
|
|
6
|
+
// * `unzipper` is a true "streaming" unpacker: it works in a "pull" fashion rather than a "push" one.
|
|
7
|
+
// New chunks of archived data are only read and decompressed as the receiver is ready to process them.
|
|
8
|
+
//
|
|
9
|
+
// * `unzipper` can completely skip a given compressed file entry if it's of no interest.
|
|
10
|
+
// This means that a `.zip` archive could be read in multiple passes without performance penalty.
|
|
11
|
+
|
|
12
|
+
import { Parse } from 'unzipper-esm';
|
|
13
|
+
import { Buffer } from 'buffer';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Reads `*.zip` file contents.
|
|
17
|
+
* @param {Stream} stream
|
|
18
|
+
* @return {Promise<Record<string,Buffer>>} Resolves to an object holding `*.zip` file entries. P.S. `Buffer` is a `Uint8Array`.
|
|
19
|
+
*/
|
|
20
|
+
export default function unzipFromStream(stream) {
|
|
21
|
+
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
|
|
22
|
+
filter = _ref.filter;
|
|
23
|
+
// The `files` object stores the files and their contents.
|
|
24
|
+
var files = {};
|
|
25
|
+
var filesChunks = {};
|
|
26
|
+
var onFile = function onFile(filePath) {
|
|
27
|
+
// See if this file should be ignored.
|
|
28
|
+
// If it should, this entry won't be processed, i.e. `Unzip` will not try
|
|
29
|
+
// to decompress its data, and will just discard it.
|
|
30
|
+
if (filter && !filter({
|
|
31
|
+
path: filePath
|
|
32
|
+
})) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
filesChunks[filePath] = [];
|
|
36
|
+
};
|
|
37
|
+
var onFileData = function onFileData(filePath, chunk) {
|
|
38
|
+
filesChunks[filePath].push(chunk);
|
|
39
|
+
};
|
|
40
|
+
var onFileDataEnd = function onFileDataEnd(filePath) {
|
|
41
|
+
files[filePath] = Buffer.concat(filesChunks[filePath]);
|
|
42
|
+
delete filesChunks[filePath];
|
|
43
|
+
};
|
|
44
|
+
return unzipFromStream_(stream, onFile, onFileData, onFileDataEnd).then(function () {
|
|
45
|
+
return files;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
var PROMISE_RESOLVE_VALUE = undefined;
|
|
49
|
+
function unzipFromStream_(stream, onFile, onFileData, onFileDataEnd) {
|
|
50
|
+
return new Promise(function (resolve, reject) {
|
|
51
|
+
var promises = [];
|
|
52
|
+
var errored = false;
|
|
53
|
+
var onError = function onError(error) {
|
|
54
|
+
if (!errored) {
|
|
55
|
+
errored = true;
|
|
56
|
+
reject(error);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
stream
|
|
60
|
+
// This first "error" listener catches the original stream errors.
|
|
61
|
+
//
|
|
62
|
+
// That's because the .pipe() method does not automatically propagate errors
|
|
63
|
+
// from a source (input) stream to the destination stream or the end of the pipeline.
|
|
64
|
+
// You would need to attach an 'error' event handler to each stream in the chain.
|
|
65
|
+
//
|
|
66
|
+
// A more convenient alternative would be to use `stream.pipeline()` function:
|
|
67
|
+
// `pipeline(stream1, stream2, (error) => { ... })`
|
|
68
|
+
//
|
|
69
|
+
.on('error', onError)
|
|
70
|
+
// Pipe the input stream through the unzipper stream.
|
|
71
|
+
.pipe(Parse())
|
|
72
|
+
// This second "error" listener catches the unzipper stream errors.
|
|
73
|
+
//
|
|
74
|
+
// That's because the .pipe() method does not automatically propagate errors
|
|
75
|
+
// from a source (input) stream to the destination stream or the end of the pipeline.
|
|
76
|
+
// You would need to attach an 'error' event handler to each stream in the chain.
|
|
77
|
+
//
|
|
78
|
+
// A more convenient alternative would be to use `stream.pipeline()` function:
|
|
79
|
+
// `pipeline(stream1, stream2, (error) => { ... })`
|
|
80
|
+
//
|
|
81
|
+
.on('error', onError)
|
|
82
|
+
// The unzipper stream is closed when all `entries` have been reported.
|
|
83
|
+
.on('finish', function () {
|
|
84
|
+
if (!errored) {
|
|
85
|
+
// Wait for all `entries` to be read.
|
|
86
|
+
// The second argument of `.then()` function is not required
|
|
87
|
+
// but I didn't remove it just to potentially prevent any potential silly bugs
|
|
88
|
+
// in case of some potential changes in some potential future.
|
|
89
|
+
Promise.all(promises).then(function () {
|
|
90
|
+
resolve(PROMISE_RESOLVE_VALUE);
|
|
91
|
+
}, onError);
|
|
92
|
+
}
|
|
93
|
+
}).on('entry', function (entry) {
|
|
94
|
+
// See if this file should be ignored.
|
|
95
|
+
var ignore = false;
|
|
96
|
+
// `entry.type` could be 'Directory' or 'File'.
|
|
97
|
+
// Ignore anything except files.
|
|
98
|
+
if (entry.type === 'Directory') {
|
|
99
|
+
ignore = true;
|
|
100
|
+
}
|
|
101
|
+
if (errored) {
|
|
102
|
+
ignore = true;
|
|
103
|
+
}
|
|
104
|
+
if (onFile(entry.path) === false) {
|
|
105
|
+
ignore = true;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// If this file should be ignored.
|
|
109
|
+
if (ignore) {
|
|
110
|
+
// Call `entry.autodrain()` when you do not intend to process a specific `entry`'s raw data.
|
|
111
|
+
// Otherwise, if an `entry` is not consumed (via .pipe(), .buffer(), or .autodrain()),
|
|
112
|
+
// the stream will halt, preventing further file processing.
|
|
113
|
+
entry.autodrain().on('error', onError);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
promises.push(new Promise(function (resolve) {
|
|
117
|
+
// `entry` seems to be a generic Node.js stream.
|
|
118
|
+
// `entry.pipe()` pipes the file contents to a stream.
|
|
119
|
+
// `entry.stream()` returns a readable stream.
|
|
120
|
+
// `entry.buffer()` returns a promise that resolves to a `Buffer` with the file contents.
|
|
121
|
+
entry.on('data', function (data) {
|
|
122
|
+
onFileData(entry.path, data);
|
|
123
|
+
}).on('error', function (error) {
|
|
124
|
+
onError(error);
|
|
125
|
+
}).on('finish', function () {
|
|
126
|
+
onFileDataEnd(entry.path);
|
|
127
|
+
resolve();
|
|
128
|
+
});
|
|
129
|
+
}));
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=unzipFromStream.unzipper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unzipFromStream.unzipper.js","names":["Parse","Buffer","unzipFromStream","stream","_ref","arguments","length","undefined","filter","files","filesChunks","onFile","filePath","path","onFileData","chunk","push","onFileDataEnd","concat","unzipFromStream_","then","PROMISE_RESOLVE_VALUE","Promise","resolve","reject","promises","errored","onError","error","on","pipe","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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "read-excel-file",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.0",
|
|
4
4
|
"description": "Read `.xlsx` files in a web browser or in Node.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -28,14 +28,15 @@
|
|
|
28
28
|
},
|
|
29
29
|
"sideEffects": false,
|
|
30
30
|
"scripts": {
|
|
31
|
-
"test": "mocha --bail \"source/**/*.test.js\" \"test/*.test.js\" \"test/!(exports|benchmark)/**/*.test.js\"",
|
|
31
|
+
"test": "mocha --bail \"source/**/*.test.js\" \"test/*.test.js\" \"test/!(exports|benchmark|benchmark-unzipFromStream)/**/*.test.js\"",
|
|
32
32
|
"test:exports": "mocha --bail \"test/exports/**/*.test.js\"",
|
|
33
33
|
"test:benchmark": "mocha --bail \"test/benchmark/**/*.test.js\"",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
34
|
+
"test:benchmark:unzipFromStream": "mocha --bail \"test/benchmark-unzipFromStream/**/*.test.js\"",
|
|
35
|
+
"clean-for-build": "rimraf ./commonjs ./modules",
|
|
36
|
+
"build-es6-modules": "cross-env BABEL_ENV=es6 babel ./source --out-dir ./modules --source-maps",
|
|
37
|
+
"build-commonjs-modules": "cross-env BABEL_ENV=commonjs babel ./source --out-dir ./commonjs --source-maps",
|
|
36
38
|
"build-commonjs-package.json": "node build-scripts/create-commonjs-package-json.js",
|
|
37
39
|
"build-commonjs": "npm-run-all build-commonjs-modules build-commonjs-package.json",
|
|
38
|
-
"build-es6-modules": "better-npm-run build-es6-modules",
|
|
39
40
|
"browser-build": "rollup --config rollup.config.mjs",
|
|
40
41
|
"build": "npm-run-all clean-for-build build-commonjs build-es6-modules browser-build",
|
|
41
42
|
"prepublishOnly": "npm-run-all build test test:exports browser-build"
|
|
@@ -44,8 +45,8 @@
|
|
|
44
45
|
"node": ">=18"
|
|
45
46
|
},
|
|
46
47
|
"dependencies": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
48
|
+
"fflate": "^0.8.3",
|
|
49
|
+
"unzipper-esm": "^0.13.2"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@babel/cli": "^7.17.10",
|
|
@@ -54,40 +55,19 @@
|
|
|
54
55
|
"@babel/plugin-transform-for-of": "^7.17.12",
|
|
55
56
|
"@babel/plugin-transform-runtime": "^7.17.12",
|
|
56
57
|
"@babel/preset-env": "^7.17.12",
|
|
57
|
-
"@babel/register": "^7.17.7",
|
|
58
|
-
"better-npm-run": "^0.1.1",
|
|
59
58
|
"chai": "^4.3.6",
|
|
60
59
|
"core-js": "^3.22.5",
|
|
60
|
+
"cross-env": "^10.1.0",
|
|
61
61
|
"mocha": "^10.0.0",
|
|
62
62
|
"npm-run-all": "^4.1.5",
|
|
63
|
-
"
|
|
64
|
-
"rimraf": "^3.0.2",
|
|
63
|
+
"rimraf": "^6.1.3",
|
|
65
64
|
"rollup": "^2.73.0",
|
|
66
65
|
"rollup-plugin-commonjs": "^10.1.0",
|
|
67
66
|
"rollup-plugin-json": "^4.0.0",
|
|
68
67
|
"rollup-plugin-node-resolve": "^5.2.0",
|
|
69
68
|
"rollup-plugin-terser": "^7.0.2",
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"betterScripts": {
|
|
73
|
-
"browser-build": {
|
|
74
|
-
"command": "webpack --mode production --progress --colors",
|
|
75
|
-
"env": {
|
|
76
|
-
"WEBPACK_ENV": "build"
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
"build-commonjs-modules": {
|
|
80
|
-
"command": "babel ./source --out-dir ./commonjs --source-maps",
|
|
81
|
-
"env": {
|
|
82
|
-
"BABEL_ENV": "commonjs"
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
"build-es6-modules": {
|
|
86
|
-
"command": "babel ./source --out-dir ./modules --source-maps",
|
|
87
|
-
"env": {
|
|
88
|
-
"BABEL_ENV": "es6"
|
|
89
|
-
}
|
|
90
|
-
}
|
|
69
|
+
"sax": "^1.6.0",
|
|
70
|
+
"saxen": "^11.0.2"
|
|
91
71
|
},
|
|
92
72
|
"repository": {
|
|
93
73
|
"type": "git",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseCellCoordinates.js","names":["parseCellCoordinates","coordinatesString","_coordinatesString$sp","split","_coordinatesString$sp2","_slicedToArray","column","row","Number","getColumnNumberFromColumnLetters","trim","LETTERS","columnLetters","n","i","length","indexOf"],"sources":["../../source/xlsx/parseCellCoordinates.js"],"sourcesContent":["export default function parseCellCoordinates(coordinatesString) {\r\n // Coordinate examples: \"AA2091\", \"R988\", \"B1\".\r\n const [column, row] = coordinatesString.split(/(\\d+)/)\r\n return [\r\n // Row.\r\n Number(row),\r\n // Column.\r\n\t\t// It's not clear why would `column` ever be non-trimmed,\r\n\t\t// but if it was added here then perhaps it could hypothetically happen, or smth.\r\n getColumnNumberFromColumnLetters(column.trim())\r\n ]\r\n}\r\n\r\n// Maps \"A1\"-like coordinates to `{ row, column }` numeric coordinates.\r\nconst LETTERS = [\"\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\", \"G\", \"H\", \"I\", \"J\", \"K\", \"L\", \"M\", \"N\", \"O\", \"P\", \"Q\", \"R\", \"S\", \"T\", \"U\", \"V\", \"W\", \"X\", \"Y\", \"Z\"]\r\n\r\n// Converts a letter coordinate to a digit coordinate.\r\n// Examples: \"A\" -> 1, \"B\" -> 2, \"Z\" -> 26, \"AA\" -> 27, etc.\r\nfunction getColumnNumberFromColumnLetters(columnLetters) {\r\n // `for ... of ...` would require Babel polyfill for iterating a string.\r\n let n = 0\r\n let i = 0\r\n while (i < columnLetters.length) {\r\n n *= 26\r\n n += LETTERS.indexOf(columnLetters[i])\r\n i++\r\n }\r\n return n\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAAe,SAASA,oBAAoBA,CAACC,iBAAiB,EAAE;EAC9D;EACA,IAAAC,qBAAA,GAAsBD,iBAAiB,CAACE,KAAK,CAAC,OAAO,CAAC;IAAAC,sBAAA,GAAAC,cAAA,CAAAH,qBAAA;IAA/CI,MAAM,GAAAF,sBAAA;IAAEG,GAAG,GAAAH,sBAAA;EAClB,OAAO;EACL;EACAI,MAAM,CAACD,GAAG,CAAC;EACX;EACF;EACA;EACEE,gCAAgC,CAACH,MAAM,CAACI,IAAI,CAAC,CAAC,CAAC,CAChD;AACH;;AAEA;AACA,IAAMC,OAAO,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;AAEtJ;AACA;AACA,SAASF,gCAAgCA,CAACG,aAAa,EAAE;EACvD;EACA,IAAIC,CAAC,GAAG,CAAC;EACT,IAAIC,CAAC,GAAG,CAAC;EACT,OAAOA,CAAC,GAAGF,aAAa,CAACG,MAAM,EAAE;IAC/BF,CAAC,IAAI,EAAE;IACPA,CAAC,IAAIF,OAAO,CAACK,OAAO,CAACJ,aAAa,CAACE,CAAC,CAAC,CAAC;IACtCA,CAAC,EAAE;EACL;EACA,OAAOD,CAAC;AACV"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports["default"] = parseCells;
|
|
7
|
-
var _xlsx = require("../xml/xlsx.js");
|
|
8
|
-
var _parseCell = _interopRequireDefault(require("./parseCell.js"));
|
|
9
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
|
|
10
|
-
function parseCells(sheetDocument, sharedStrings, styles, epoch1904, options) {
|
|
11
|
-
var cells = (0, _xlsx.getCellElements)(sheetDocument);
|
|
12
|
-
if (cells.length === 0) {
|
|
13
|
-
return [];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// It seems like the idea of parsing "merged cells" was abandoned without being finished.
|
|
17
|
-
// Here, it seems to just get to the stage of parsing merged cell coordinates.
|
|
18
|
-
// Perhaps it's because it's not clear how would the package return merged cell results.
|
|
19
|
-
// I.e. should it just duplicate the value in each one of the merged cells?
|
|
20
|
-
// Or should it keep the existing behavior of only returning the value of the top-most left-most cell
|
|
21
|
-
// and then return `null` for the other ones?
|
|
22
|
-
// Perhaps the latter (existing) approach was found to be the most sensible.
|
|
23
|
-
//
|
|
24
|
-
// const mergedCells = getMergedCellCoordinates(sheetDocument)
|
|
25
|
-
// for (const mergedCell of mergedCells) {
|
|
26
|
-
// const [from, to] = mergedCell.split(':').map(parseCellCoordinates)
|
|
27
|
-
// console.log('Merged Cell.', 'From:', from, 'To:', to)
|
|
28
|
-
// }
|
|
29
|
-
|
|
30
|
-
return cells.map(function (element) {
|
|
31
|
-
return (0, _parseCell["default"])(element, sheetDocument, sharedStrings, styles, epoch1904, options);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
//# sourceMappingURL=parseCells.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseCells.js","names":["_xlsx","require","_parseCell","_interopRequireDefault","obj","__esModule","parseCells","sheetDocument","sharedStrings","styles","epoch1904","options","cells","getCellElements","length","map","element","parseCell"],"sources":["../../source/xlsx/parseCells.js"],"sourcesContent":["import { getCellElements } from '../xml/xlsx.js'\r\n\r\nimport parseCell from './parseCell.js'\r\n\r\nexport default function parseCells(sheetDocument, sharedStrings, styles, epoch1904, options) {\r\n const cells = getCellElements(sheetDocument)\r\n\r\n if (cells.length === 0) {\r\n return []\r\n }\r\n\r\n // It seems like the idea of parsing \"merged cells\" was abandoned without being finished.\r\n // Here, it seems to just get to the stage of parsing merged cell coordinates.\r\n // Perhaps it's because it's not clear how would the package return merged cell results.\r\n // I.e. should it just duplicate the value in each one of the merged cells?\r\n // Or should it keep the existing behavior of only returning the value of the top-most left-most cell\r\n // and then return `null` for the other ones?\r\n // Perhaps the latter (existing) approach was found to be the most sensible.\r\n //\r\n // const mergedCells = getMergedCellCoordinates(sheetDocument)\r\n // for (const mergedCell of mergedCells) {\r\n // const [from, to] = mergedCell.split(':').map(parseCellCoordinates)\r\n // console.log('Merged Cell.', 'From:', from, 'To:', to)\r\n // }\r\n\r\n return cells.map((element) => {\r\n return parseCell(element, sheetDocument, sharedStrings, styles, epoch1904, options)\r\n })\r\n}"],"mappings":";;;;;;AAAA,IAAAA,KAAA,GAAAC,OAAA;AAEA,IAAAC,UAAA,GAAAC,sBAAA,CAAAF,OAAA;AAAsC,SAAAE,uBAAAC,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,gBAAAA,GAAA;AAEvB,SAASE,UAAUA,CAACC,aAAa,EAAEC,aAAa,EAAEC,MAAM,EAAEC,SAAS,EAAEC,OAAO,EAAE;EAC3F,IAAMC,KAAK,GAAG,IAAAC,qBAAe,EAACN,aAAa,CAAC;EAE5C,IAAIK,KAAK,CAACE,MAAM,KAAK,CAAC,EAAE;IACtB,OAAO,EAAE;EACX;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA,OAAOF,KAAK,CAACG,GAAG,CAAC,UAACC,OAAO,EAAK;IAC5B,OAAO,IAAAC,qBAAS,EAACD,OAAO,EAAET,aAAa,EAAEC,aAAa,EAAEC,MAAM,EAAEC,SAAS,EAAEC,OAAO,CAAC;EACrF,CAAC,CAAC;AACJ"}
|