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.
Files changed (205) hide show
  1. package/.gitlab-ci.yml +1 -1
  2. package/CHANGELOG.md +5 -0
  3. package/README.md +153 -50
  4. package/bundle/read-excel-file.min.js +1 -1
  5. package/bundle/read-excel-file.min.js.map +1 -1
  6. package/bundle/read-excel-file.min.old.js +2 -0
  7. package/bundle/read-excel-file.min.old.js.map +1 -0
  8. package/commonjs/export/convertValuesFromUint8ArraysToStrings.js +3 -0
  9. package/commonjs/export/convertValuesFromUint8ArraysToStrings.js.map +1 -1
  10. package/commonjs/export/parseSheet.js +12 -9
  11. package/commonjs/export/parseSheet.js.map +1 -1
  12. package/commonjs/export/readSheetBrowser.js +6 -2
  13. package/commonjs/export/readSheetBrowser.js.map +1 -1
  14. package/commonjs/export/readSheetNode.js +6 -2
  15. package/commonjs/export/readSheetNode.js.map +1 -1
  16. package/commonjs/export/readSheetUniversal.js +14 -2
  17. package/commonjs/export/readSheetUniversal.js.map +1 -1
  18. package/commonjs/export/readSheetWebWorker.js +12 -2
  19. package/commonjs/export/readSheetWebWorker.js.map +1 -1
  20. package/commonjs/export/readXlsxFileBrowser.js +6 -2
  21. package/commonjs/export/readXlsxFileBrowser.js.map +1 -1
  22. package/commonjs/export/readXlsxFileNode.js +6 -2
  23. package/commonjs/export/readXlsxFileNode.js.map +1 -1
  24. package/commonjs/export/readXlsxFileUniversal.js +14 -2
  25. package/commonjs/export/readXlsxFileUniversal.js.map +1 -1
  26. package/commonjs/export/readXlsxFileWebWorker.js +12 -2
  27. package/commonjs/export/readXlsxFileWebWorker.js.map +1 -1
  28. package/commonjs/export/unpackXlsxFileBrowser.js +29 -6
  29. package/commonjs/export/unpackXlsxFileBrowser.js.map +1 -1
  30. package/commonjs/export/unpackXlsxFileNode.js +6 -0
  31. package/commonjs/export/unpackXlsxFileNode.js.map +1 -1
  32. package/commonjs/export/unpackXlsxFileUniversal.js +6 -0
  33. package/commonjs/export/unpackXlsxFileUniversal.js.map +1 -1
  34. package/commonjs/export/unpackXlsxFileWebWorker.js +14 -0
  35. package/commonjs/export/unpackXlsxFileWebWorker.js.map +1 -0
  36. package/commonjs/parseSheetData/parseSheetData.js +6 -6
  37. package/commonjs/parseSheetData/parseSheetData.js.map +1 -1
  38. package/commonjs/utility/checkpoint.js +33 -0
  39. package/commonjs/utility/checkpoint.js.map +1 -0
  40. package/commonjs/utility/isObject.js +15 -0
  41. package/commonjs/utility/isObject.js.map +1 -0
  42. package/commonjs/utility/isPromise.js +18 -0
  43. package/commonjs/utility/isPromise.js.map +1 -0
  44. package/commonjs/xlsx/convertCellsToData2dArray.js +0 -3
  45. package/commonjs/xlsx/convertCellsToData2dArray.js.map +1 -1
  46. package/commonjs/xlsx/isDateFormatStyle.js +2 -2
  47. package/commonjs/xlsx/isDateFormatStyle.js.map +1 -1
  48. package/commonjs/xlsx/parseCell.js +89 -24
  49. package/commonjs/xlsx/parseCell.js.map +1 -1
  50. package/{modules/xlsx/parseCellCoordinates.js → commonjs/xlsx/parseCellAddress.js} +18 -7
  51. package/commonjs/xlsx/parseCellAddress.js.map +1 -0
  52. package/commonjs/xlsx/parseCellValue.js +7 -23
  53. package/commonjs/xlsx/parseCellValue.js.map +1 -1
  54. package/commonjs/xlsx/parseFilePaths.js +31 -32
  55. package/commonjs/xlsx/parseFilePaths.js.map +1 -1
  56. package/commonjs/xlsx/parseNumber.js +20 -0
  57. package/commonjs/xlsx/parseNumber.js.map +1 -0
  58. package/commonjs/xlsx/parseSharedString.js +64 -0
  59. package/commonjs/xlsx/parseSharedString.js.map +1 -0
  60. package/commonjs/xlsx/parseSharedStrings.js +45 -5
  61. package/commonjs/xlsx/parseSharedStrings.js.map +1 -1
  62. package/commonjs/xlsx/parseSheet.js +93 -9
  63. package/commonjs/xlsx/parseSheet.js.map +1 -1
  64. package/commonjs/xlsx/parseSheetData.js +68 -0
  65. package/commonjs/xlsx/parseSheetData.js.map +1 -0
  66. package/commonjs/xlsx/parseSpreadsheetContents.js +244 -43
  67. package/commonjs/xlsx/parseSpreadsheetContents.js.map +1 -1
  68. package/commonjs/xlsx/parseSpreadsheetInfo.js +67 -36
  69. package/commonjs/xlsx/parseSpreadsheetInfo.js.map +1 -1
  70. package/commonjs/xlsx/parseStyles.js +89 -36
  71. package/commonjs/xlsx/parseStyles.js.map +1 -1
  72. package/commonjs/xml/dom.js +2 -1
  73. package/commonjs/xml/dom.js.map +1 -1
  74. package/commonjs/xml/parseXmlStream.js +14 -0
  75. package/commonjs/xml/parseXmlStream.js.map +1 -0
  76. package/commonjs/xml/parseXmlStream.sax.js +109 -0
  77. package/commonjs/xml/parseXmlStream.sax.js.map +1 -0
  78. package/commonjs/xml/parseXmlStream.saxen.code.js +953 -0
  79. package/commonjs/xml/parseXmlStream.saxen.code.js.map +1 -0
  80. package/commonjs/xml/parseXmlStream.saxen.js +85 -0
  81. package/commonjs/xml/parseXmlStream.saxen.js.map +1 -0
  82. package/commonjs/xml/xlsx.js +75 -40
  83. package/commonjs/xml/xlsx.js.map +1 -1
  84. package/commonjs/zip/unzipFromArrayBuffer.js +5 -14
  85. package/commonjs/zip/unzipFromArrayBuffer.js.map +1 -1
  86. package/commonjs/zip/unzipFromStream.fflate.js +154 -25
  87. package/commonjs/zip/unzipFromStream.fflate.js.map +1 -1
  88. package/commonjs/zip/unzipFromStream.js.map +1 -1
  89. package/commonjs/zip/unzipFromStream.unzipper.js +37 -26
  90. package/commonjs/zip/unzipFromStream.unzipper.js.map +1 -1
  91. package/modules/export/convertValuesFromUint8ArraysToStrings.js +2 -0
  92. package/modules/export/convertValuesFromUint8ArraysToStrings.js.map +1 -1
  93. package/modules/export/parseSheet.js +12 -9
  94. package/modules/export/parseSheet.js.map +1 -1
  95. package/modules/export/readSheetBrowser.js +5 -2
  96. package/modules/export/readSheetBrowser.js.map +1 -1
  97. package/modules/export/readSheetNode.js +5 -2
  98. package/modules/export/readSheetNode.js.map +1 -1
  99. package/modules/export/readSheetUniversal.js +14 -2
  100. package/modules/export/readSheetUniversal.js.map +1 -1
  101. package/modules/export/readSheetWebWorker.js +12 -2
  102. package/modules/export/readSheetWebWorker.js.map +1 -1
  103. package/modules/export/readXlsxFileBrowser.js +5 -2
  104. package/modules/export/readXlsxFileBrowser.js.map +1 -1
  105. package/modules/export/readXlsxFileNode.js +5 -2
  106. package/modules/export/readXlsxFileNode.js.map +1 -1
  107. package/modules/export/readXlsxFileUniversal.js +14 -2
  108. package/modules/export/readXlsxFileUniversal.js.map +1 -1
  109. package/modules/export/readXlsxFileWebWorker.js +12 -2
  110. package/modules/export/readXlsxFileWebWorker.js.map +1 -1
  111. package/modules/export/unpackXlsxFileBrowser.js +26 -6
  112. package/modules/export/unpackXlsxFileBrowser.js.map +1 -1
  113. package/modules/export/unpackXlsxFileNode.js +3 -0
  114. package/modules/export/unpackXlsxFileNode.js.map +1 -1
  115. package/modules/export/unpackXlsxFileUniversal.js +3 -0
  116. package/modules/export/unpackXlsxFileUniversal.js.map +1 -1
  117. package/modules/export/unpackXlsxFileWebWorker.js +6 -0
  118. package/modules/export/unpackXlsxFileWebWorker.js.map +1 -0
  119. package/modules/parseSheetData/parseSheetData.js +4 -4
  120. package/modules/parseSheetData/parseSheetData.js.map +1 -1
  121. package/modules/utility/checkpoint.js +25 -0
  122. package/modules/utility/checkpoint.js.map +1 -0
  123. package/modules/utility/isObject.js +9 -0
  124. package/modules/utility/isObject.js.map +1 -0
  125. package/modules/utility/isPromise.js +12 -0
  126. package/modules/utility/isPromise.js.map +1 -0
  127. package/modules/xlsx/convertCellsToData2dArray.js +0 -3
  128. package/modules/xlsx/convertCellsToData2dArray.js.map +1 -1
  129. package/modules/xlsx/isDateFormatStyle.js +2 -2
  130. package/modules/xlsx/isDateFormatStyle.js.map +1 -1
  131. package/modules/xlsx/parseCell.js +85 -24
  132. package/modules/xlsx/parseCell.js.map +1 -1
  133. package/{commonjs/xlsx/parseCellCoordinates.js → modules/xlsx/parseCellAddress.js} +12 -13
  134. package/modules/xlsx/parseCellAddress.js.map +1 -0
  135. package/modules/xlsx/parseCellValue.js +7 -23
  136. package/modules/xlsx/parseCellValue.js.map +1 -1
  137. package/modules/xlsx/parseFilePaths.js +31 -33
  138. package/modules/xlsx/parseFilePaths.js.map +1 -1
  139. package/modules/xlsx/parseNumber.js +14 -0
  140. package/modules/xlsx/parseNumber.js.map +1 -0
  141. package/modules/xlsx/parseSharedString.js +55 -0
  142. package/modules/xlsx/parseSharedString.js.map +1 -0
  143. package/modules/xlsx/parseSharedStrings.js +46 -5
  144. package/modules/xlsx/parseSharedStrings.js.map +1 -1
  145. package/modules/xlsx/parseSheet.js +91 -9
  146. package/modules/xlsx/parseSheet.js.map +1 -1
  147. package/modules/xlsx/parseSheetData.js +55 -0
  148. package/modules/xlsx/parseSheetData.js.map +1 -0
  149. package/modules/xlsx/parseSpreadsheetContents.js +242 -43
  150. package/modules/xlsx/parseSpreadsheetContents.js.map +1 -1
  151. package/modules/xlsx/parseSpreadsheetInfo.js +67 -37
  152. package/modules/xlsx/parseSpreadsheetInfo.js.map +1 -1
  153. package/modules/xlsx/parseStyles.js +88 -36
  154. package/modules/xlsx/parseStyles.js.map +1 -1
  155. package/modules/xml/dom.js +2 -1
  156. package/modules/xml/dom.js.map +1 -1
  157. package/modules/xml/parseXmlStream.js +18 -0
  158. package/modules/xml/parseXmlStream.js.map +1 -0
  159. package/modules/xml/parseXmlStream.sax.js +103 -0
  160. package/modules/xml/parseXmlStream.sax.js.map +1 -0
  161. package/modules/xml/parseXmlStream.saxen.code.js +947 -0
  162. package/modules/xml/parseXmlStream.saxen.code.js.map +1 -0
  163. package/modules/xml/parseXmlStream.saxen.js +79 -0
  164. package/modules/xml/parseXmlStream.saxen.js.map +1 -0
  165. package/modules/xml/xlsx.js +72 -36
  166. package/modules/xml/xlsx.js.map +1 -1
  167. package/modules/zip/unzipFromArrayBuffer.js +5 -14
  168. package/modules/zip/unzipFromArrayBuffer.js.map +1 -1
  169. package/modules/zip/unzipFromStream.fflate.js +157 -24
  170. package/modules/zip/unzipFromStream.fflate.js.map +1 -1
  171. package/modules/zip/unzipFromStream.js +56 -2
  172. package/modules/zip/unzipFromStream.js.map +1 -1
  173. package/modules/zip/unzipFromStream.unzipper.js +38 -26
  174. package/modules/zip/unzipFromStream.unzipper.js.map +1 -1
  175. package/package.json +4 -6
  176. package/commonjs/xlsx/parseCellCoordinates.js.map +0 -1
  177. package/commonjs/xlsx/parseCells.js +0 -34
  178. package/commonjs/xlsx/parseCells.js.map +0 -1
  179. package/commonjs/xlsx/parseSheetDimensions.js +0 -43
  180. package/commonjs/xlsx/parseSheetDimensions.js.map +0 -1
  181. package/commonjs/xml/xml.js +0 -13
  182. package/commonjs/xml/xml.js.map +0 -1
  183. package/commonjs/xml/xmlBrowser.js +0 -17
  184. package/commonjs/xml/xmlBrowser.js.map +0 -1
  185. package/commonjs/xml/xpath/xlsx-xpath.js +0 -92
  186. package/commonjs/xml/xpath/xlsx-xpath.js.map +0 -1
  187. package/commonjs/xml/xpath/xpathBrowser.js +0 -33
  188. package/commonjs/xml/xpath/xpathBrowser.js.map +0 -1
  189. package/commonjs/xml/xpath/xpathNode.js +0 -16
  190. package/commonjs/xml/xpath/xpathNode.js.map +0 -1
  191. package/modules/xlsx/parseCellCoordinates.js.map +0 -1
  192. package/modules/xlsx/parseCells.js +0 -27
  193. package/modules/xlsx/parseCells.js.map +0 -1
  194. package/modules/xlsx/parseSheetDimensions.js +0 -37
  195. package/modules/xlsx/parseSheetDimensions.js.map +0 -1
  196. package/modules/xml/xml.js +0 -7
  197. package/modules/xml/xml.js.map +0 -1
  198. package/modules/xml/xmlBrowser.js +0 -11
  199. package/modules/xml/xmlBrowser.js.map +0 -1
  200. package/modules/xml/xpath/xlsx-xpath.js +0 -73
  201. package/modules/xml/xpath/xlsx-xpath.js.map +0 -1
  202. package/modules/xml/xpath/xpathBrowser.js +0 -27
  203. package/modules/xml/xpath/xpathBrowser.js.map +0 -1
  204. package/modules/xml/xpath/xpathNode.js +0 -9
  205. 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
- // `fflate` uses a javascript-only implementation of `.zip` compression/decompression.
10
- // This means that it could likely be less performant than Node.js's "native" `zlib` module`.
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
- // with `UnzipInflate` decompression implementation to decompress the data
41
- // that was previously compressed using `DEFLATE` compressing algorithm,
42
- // which is what `*.xlsx` files use.
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
- var chunks = [];
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
- chunks.push(chunk);
186
+ onFileData(entry.name, chunk);
115
187
  if (isLast) {
116
- files[entry.name] = _nodeBuffer.Buffer.concat(chunks);
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(_fflate.UnzipInflate);
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
- // The `.push()` function is synchronous, meaning that by the time it returns,
147
- // any complete files entries encountered so far have already been decompressed
148
- // and populated in the `files` object.
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
- // Resolve with the unzipped files.
168
- resolve(files);
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":"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"}
@@ -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":";;;;;;;;;;;AAYA,IAAAA,wBAAA,GAAAC,sBAAA,CAAAC,OAAA;AAAkE,SAAAD,uBAAAE,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,gBAAAA,GAAA"}
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
- // `unzipper` uses Node.js native `zlib` module.
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
- // When not forking to apply the fix, a workaround could be to install "@aws-sdk/client-s3"
20
- // package manually, which introduces unnecessary complexity and "esoteric knowledge" to the application setup.
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
- // Another workaround could be to "alias" "@aws-sdk/client-s3" package in a "bundler" configuration file
23
- // with a path to a `*.js` file containing just "export default null". But that kind of a workaround would also
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(files);
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 (filter) {
94
- if (!filter({
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
- chunks.push(data);
127
+ onFileData(entry.path, data);
117
128
  }).on('error', function (error) {
118
129
  onError(error);
119
130
  }).on('finish', function () {
120
- files[entry.path] = _buffer.Buffer.concat(chunks);
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","Promise","resolve","reject","promises","errored","onError","error","on","pipe","Parse","all","then","entry","ignore","type","path","autodrain","chunks","push","data","Buffer","concat"],"sources":["../../source/zip/unzipFromStream.unzipper.js"],"sourcesContent":["// `unzipper` uses Node.js native `zlib` module.\r\n// This means that most likely it's more performant than an equivalent javascript-only implementation.\r\n\r\n// `unzipper` has a bug — it is written in CommonJS and uses a conditional `require()` call\r\n// to create an AWS S3 client instance: `require('@aws-sdk/client-s3')`.\r\n// https://github.com/ZJONSSON/node-unzipper/issues/330\r\n// The author of the package refuses to acknowledge the issue and apply a simple fix.\r\n// The package, therefore, looks like an \"abandonware\".\r\n// Someone could easily fix the issue though by forking the package.\r\n//\r\n// When not forking to apply the fix, a workaround could be to install \"@aws-sdk/client-s3\"\r\n// package manually, which introduces unnecessary complexity and \"esoteric knowledge\" to the application setup.\r\n//\r\n// Another workaround could be to \"alias\" \"@aws-sdk/client-s3\" package in a \"bundler\" configuration file\r\n// with a path to a `*.js` file containing just \"export default null\". But that kind of a workaround would also\r\n// result in errors when using other packages that happen to `import` anything from \"@aws-sdk/client-s3\" package,\r\n// so it's not really a workaround but more of a ticking bomb. Not to mention that it introduces\r\n// unnecessary complexity and \"esoteric knowledge\" to the application setup.\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\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(files)\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 (filter) {\r\n\t\t\t\t\tif (!filter({ path: entry.path })) {\r\n\t\t\t\t\t\tignore = true\r\n\t\t\t\t\t}\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\tconst chunks = []\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\tchunks.push(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\tfiles[entry.path] = Buffer.concat(chunks)\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
+ {"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;;AAElC;AACA;AACA;AACA;AACA,eAAe,SAASC,qCAAqCA,CAACC,OAAO,EAAE;EACtE,IAAMC,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,GAAGT,SAAS,CAACE,OAAO,CAACO,GAAG,CAAC,CAAC;EAChD;EACA,OAAON,gBAAgB;AACxB"}
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 {Sheet[]}
17
+ * @return {Promise<SheetData>}
17
18
  */
18
- export default function parseSheet(contents, xml, sheet, options) {
19
- var data = parseSpreadsheetContents(contents, xml, _objectSpread(_objectSpread({}, options), {}, {
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
- }))[0].data;
22
- if (options && options.schema) {
23
- return parseSheetData(data, options.schema);
24
- }
25
- return data;
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","contents","xml","sheet","options","data","_objectSpread","sheets","undefined","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 {Record<string,string>} contents - A map of `.xml` files inside the `.xlsx` file (which itself is just a zipped directory).\r\n * @param {object} xml — An object having a single property — `createDocument(string)` function.\r\n * @param {string|number} [sheet] — Sheet name or number.\r\n * @param {object} [options]\r\n * @return {Sheet[]}\r\n */\r\nexport default function parseSheet(contents, xml, sheet, options) {\r\n\tconst { data } = parseSpreadsheetContents(contents, xml, {\r\n\t\t...options,\r\n\t\tsheets: [sheet === undefined ? 1 : sheet]\r\n\t})[0]\r\n\r\n\tif (options && options.schema) {\r\n\t\treturn parseSheetData(data, options.schema)\r\n\t}\r\n\r\n\treturn data\r\n}"],"mappings":";;;;;;AAAA,OAAOA,wBAAwB,MAAM,qCAAqC;AAC1E,OAAOC,cAAc,MAAM,qCAAqC;;AAEhE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,SAASC,UAAUA,CAACC,QAAQ,EAAEC,GAAG,EAAEC,KAAK,EAAEC,OAAO,EAAE;EACjE,IAAQC,IAAI,GAAKP,wBAAwB,CAACG,QAAQ,EAAEC,GAAG,EAAAI,aAAA,CAAAA,aAAA,KACnDF,OAAO;IACVG,MAAM,EAAE,CAACJ,KAAK,KAAKK,SAAS,GAAG,CAAC,GAAGL,KAAK;EAAC,EACzC,CAAC,CAAC,CAAC,CAAC,CAHGE,IAAI;EAKZ,IAAID,OAAO,IAAIA,OAAO,CAACK,MAAM,EAAE;IAC9B,OAAOV,cAAc,CAACM,IAAI,EAAED,OAAO,CAACK,MAAM,CAAC;EAC5C;EAEA,OAAOJ,IAAI;AACZ"}
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"}