@cj-tech-master/excelts 1.0.0 → 1.4.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.
Files changed (69) hide show
  1. package/dist/browser/excelts.iife.js +2568 -1188
  2. package/dist/browser/excelts.iife.js.map +1 -1
  3. package/dist/browser/excelts.iife.min.js +21 -19
  4. package/dist/cjs/index.js +1 -0
  5. package/dist/cjs/stream/xlsx/workbook-reader.js +2 -2
  6. package/dist/cjs/stream/xlsx/workbook-writer.js +8 -4
  7. package/dist/cjs/utils/cell-format.js +815 -0
  8. package/dist/cjs/utils/cell-matrix.js +37 -2
  9. package/dist/cjs/utils/parse-sax.js +2 -2
  10. package/dist/cjs/utils/sheet-utils.js +615 -0
  11. package/dist/cjs/utils/stream-buf.js +15 -4
  12. package/dist/cjs/utils/unzip/buffer-stream.js +27 -0
  13. package/dist/cjs/utils/unzip/index.js +23 -0
  14. package/dist/cjs/utils/unzip/noop-stream.js +20 -0
  15. package/dist/cjs/utils/unzip/parse-buffer.js +60 -0
  16. package/dist/cjs/utils/unzip/parse-datetime.js +23 -0
  17. package/dist/cjs/utils/unzip/parse-extra-field.js +52 -0
  18. package/dist/cjs/utils/unzip/parse.js +340 -0
  19. package/dist/cjs/utils/unzip/pull-stream.js +145 -0
  20. package/dist/cjs/utils/utils.js +13 -17
  21. package/dist/cjs/utils/zip-stream.js +29 -33
  22. package/dist/cjs/xlsx/xlsx.js +1 -2
  23. package/dist/esm/index.browser.js +1 -0
  24. package/dist/esm/index.js +1 -0
  25. package/dist/esm/stream/xlsx/workbook-reader.js +2 -2
  26. package/dist/esm/stream/xlsx/workbook-writer.js +9 -5
  27. package/dist/esm/utils/cell-format.js +810 -0
  28. package/dist/esm/utils/cell-matrix.js +37 -2
  29. package/dist/esm/utils/parse-sax.js +1 -1
  30. package/dist/esm/utils/sheet-utils.js +595 -0
  31. package/dist/esm/utils/stream-buf.js +15 -4
  32. package/dist/esm/utils/unzip/buffer-stream.js +24 -0
  33. package/dist/esm/utils/unzip/index.js +12 -0
  34. package/dist/esm/utils/unzip/noop-stream.js +16 -0
  35. package/dist/esm/utils/unzip/parse-buffer.js +57 -0
  36. package/dist/esm/utils/unzip/parse-datetime.js +20 -0
  37. package/dist/esm/utils/unzip/parse-extra-field.js +49 -0
  38. package/dist/esm/utils/unzip/parse.js +332 -0
  39. package/dist/esm/utils/unzip/pull-stream.js +141 -0
  40. package/dist/esm/utils/utils.js +12 -16
  41. package/dist/esm/utils/zip-stream.js +30 -34
  42. package/dist/esm/xlsx/xlsx.js +1 -2
  43. package/dist/types/doc/column.d.ts +1 -1
  44. package/dist/types/doc/worksheet.d.ts +2 -2
  45. package/dist/types/index.browser.d.ts +1 -0
  46. package/dist/types/index.d.ts +1 -0
  47. package/dist/types/stream/xlsx/workbook-writer.d.ts +1 -0
  48. package/dist/types/utils/cell-format.d.ts +32 -0
  49. package/dist/types/utils/sheet-utils.d.ts +203 -0
  50. package/dist/types/utils/unzip/buffer-stream.d.ts +9 -0
  51. package/dist/types/utils/unzip/index.d.ts +12 -0
  52. package/dist/types/utils/unzip/noop-stream.d.ts +13 -0
  53. package/dist/types/utils/unzip/parse-buffer.d.ts +24 -0
  54. package/dist/types/utils/unzip/parse-datetime.d.ts +12 -0
  55. package/dist/types/utils/unzip/parse-extra-field.d.ts +18 -0
  56. package/dist/types/utils/unzip/parse.d.ts +70 -0
  57. package/dist/types/utils/unzip/pull-stream.d.ts +24 -0
  58. package/dist/types/utils/utils.d.ts +5 -2
  59. package/dist/types/utils/zip-stream.d.ts +5 -1
  60. package/package.json +35 -32
  61. package/dist/cjs/utils/browser-buffer-decode.js +0 -13
  62. package/dist/cjs/utils/browser-buffer-encode.js +0 -13
  63. package/dist/cjs/utils/browser.js +0 -6
  64. package/dist/esm/utils/browser-buffer-decode.js +0 -11
  65. package/dist/esm/utils/browser-buffer-encode.js +0 -11
  66. package/dist/esm/utils/browser.js +0 -3
  67. package/dist/types/utils/browser-buffer-decode.d.ts +0 -2
  68. package/dist/types/utils/browser-buffer-encode.d.ts +0 -2
  69. package/dist/types/utils/browser.d.ts +0 -1
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ /**
3
+ * Unzipper pull-stream module
4
+ * Original source: https://github.com/ZJONSSON/node-unzipper
5
+ * License: MIT
6
+ * Copyright (c) 2012 - 2013 Near Infinity Corporation
7
+ * Commits in this fork are (c) Ziggy Jonsson (ziggy.jonsson.nyc@gmail.com)
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.PullStream = void 0;
11
+ const stream_1 = require("stream");
12
+ const STR_FUNCTION = "function";
13
+ class PullStream extends stream_1.Duplex {
14
+ constructor() {
15
+ super({ decodeStrings: false, objectMode: true });
16
+ this.buffer = Buffer.from("");
17
+ this.finished = false;
18
+ this.on("finish", () => {
19
+ this.finished = true;
20
+ this.emit("chunk", false);
21
+ });
22
+ }
23
+ _write(chunk, _encoding, cb) {
24
+ this.buffer = Buffer.concat([this.buffer, chunk]);
25
+ this.cb = cb;
26
+ this.emit("chunk");
27
+ }
28
+ _read() { }
29
+ /**
30
+ * The `eof` parameter is interpreted as `file_length` if the type is number
31
+ * otherwise (i.e. buffer) it is interpreted as a pattern signaling end of stream
32
+ */
33
+ stream(eof, includeEof) {
34
+ const p = new stream_1.PassThrough();
35
+ let done = false;
36
+ const cb = () => {
37
+ if (typeof this.cb === STR_FUNCTION) {
38
+ const callback = this.cb;
39
+ this.cb = undefined;
40
+ callback();
41
+ }
42
+ };
43
+ const pull = () => {
44
+ let packet;
45
+ if (this.buffer && this.buffer.length) {
46
+ if (typeof eof === "number") {
47
+ packet = this.buffer.slice(0, eof);
48
+ this.buffer = this.buffer.slice(eof);
49
+ eof -= packet.length;
50
+ done = done || !eof;
51
+ }
52
+ else {
53
+ let match = this.buffer.indexOf(eof);
54
+ if (match !== -1) {
55
+ // store signature match byte offset to allow us to reference
56
+ // this for zip64 offset
57
+ this.match = match;
58
+ if (includeEof) {
59
+ match = match + eof.length;
60
+ }
61
+ packet = this.buffer.slice(0, match);
62
+ this.buffer = this.buffer.slice(match);
63
+ done = true;
64
+ }
65
+ else {
66
+ const len = this.buffer.length - eof.length;
67
+ if (len <= 0) {
68
+ cb();
69
+ }
70
+ else {
71
+ packet = this.buffer.slice(0, len);
72
+ this.buffer = this.buffer.slice(len);
73
+ }
74
+ }
75
+ }
76
+ if (packet) {
77
+ p.write(packet, () => {
78
+ if (this.buffer.length === 0 ||
79
+ (typeof eof !== "number" && eof.length && this.buffer.length <= eof.length)) {
80
+ cb();
81
+ }
82
+ });
83
+ }
84
+ }
85
+ if (!done) {
86
+ if (this.finished) {
87
+ this.removeListener("chunk", pull);
88
+ this.emit("error", new Error("FILE_ENDED"));
89
+ return;
90
+ }
91
+ }
92
+ else {
93
+ this.removeListener("chunk", pull);
94
+ p.end();
95
+ }
96
+ };
97
+ this.on("chunk", pull);
98
+ pull();
99
+ return p;
100
+ }
101
+ pull(eof, includeEof) {
102
+ if (eof === 0) {
103
+ return Promise.resolve(Buffer.from(""));
104
+ }
105
+ // If we already have the required data in buffer
106
+ // we can resolve the request immediately
107
+ if (typeof eof === "number" && this.buffer.length > eof) {
108
+ const data = this.buffer.slice(0, eof);
109
+ this.buffer = this.buffer.slice(eof);
110
+ return Promise.resolve(data);
111
+ }
112
+ // Otherwise we stream until we have it
113
+ let buffer = Buffer.from("");
114
+ const concatStream = new stream_1.Transform({
115
+ transform(d, _e, cb) {
116
+ buffer = Buffer.concat([buffer, d]);
117
+ cb();
118
+ }
119
+ });
120
+ let rejectHandler;
121
+ let pullStreamRejectHandler;
122
+ return new Promise((resolve, reject) => {
123
+ rejectHandler = reject;
124
+ pullStreamRejectHandler = (e) => {
125
+ this.__emittedError = e;
126
+ reject(e);
127
+ };
128
+ if (this.finished) {
129
+ return reject(new Error("FILE_ENDED"));
130
+ }
131
+ this.once("error", pullStreamRejectHandler); // reject any errors from pullstream itself
132
+ this.stream(eof, includeEof)
133
+ .on("error", reject)
134
+ .pipe(concatStream)
135
+ .on("finish", () => {
136
+ resolve(buffer);
137
+ })
138
+ .on("error", reject);
139
+ }).finally(() => {
140
+ this.removeListener("error", rejectHandler);
141
+ this.removeListener("error", pullStreamRejectHandler);
142
+ });
143
+ }
144
+ }
145
+ exports.PullStream = PullStream;
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.utils = exports.inherits = void 0;
7
7
  exports.delay = delay;
8
8
  exports.nop = nop;
9
- exports.promiseImmediate = promiseImmediate;
10
9
  exports.dateToExcel = dateToExcel;
11
10
  exports.excelToDate = excelToDate;
12
11
  exports.parsePath = parsePath;
@@ -21,26 +20,12 @@ exports.parseBoolean = parseBoolean;
21
20
  exports.range = range;
22
21
  exports.toSortedArray = toSortedArray;
23
22
  exports.objectFromProps = objectFromProps;
23
+ exports.bufferToString = bufferToString;
24
24
  const fs_1 = __importDefault(require("fs"));
25
25
  function delay(ms) {
26
26
  return new Promise(resolve => setTimeout(resolve, ms));
27
27
  }
28
28
  function nop() { }
29
- function promiseImmediate(value) {
30
- return new Promise(resolve => {
31
- if (global.setImmediate) {
32
- setImmediate(() => {
33
- resolve(value);
34
- });
35
- }
36
- else {
37
- // poorman's setImmediate - must wait at least 1ms
38
- setTimeout(() => {
39
- resolve(value);
40
- }, 1);
41
- }
42
- });
43
- }
44
29
  // useful stuff
45
30
  const inherits = function (cls, superCtor, statics, prototype) {
46
31
  cls.super_ = superCtor;
@@ -213,7 +198,6 @@ function objectFromProps(props, value = null) {
213
198
  /** @deprecated Import functions directly instead of using the utils object */
214
199
  exports.utils = {
215
200
  nop,
216
- promiseImmediate,
217
201
  inherits: exports.inherits,
218
202
  dateToExcel,
219
203
  excelToDate,
@@ -232,3 +216,15 @@ exports.utils = {
232
216
  toSortedArray,
233
217
  objectFromProps
234
218
  };
219
+ // TextDecoder is available in ES2020+ and all modern browsers/Node.js
220
+ const textDecoder = new TextDecoder("utf-8");
221
+ /**
222
+ * Convert a Buffer or ArrayBuffer to a UTF-8 string
223
+ * Works in both Node.js and browser environments
224
+ */
225
+ function bufferToString(chunk) {
226
+ if (typeof chunk === "string") {
227
+ return chunk;
228
+ }
229
+ return textDecoder.decode(chunk);
230
+ }
@@ -7,8 +7,6 @@ exports.ZipWriter = void 0;
7
7
  const events_1 = __importDefault(require("events"));
8
8
  const fflate_1 = require("fflate");
9
9
  const stream_buf_js_1 = require("./stream-buf");
10
- const browser_buffer_encode_js_1 = require("./browser-buffer-encode");
11
- const browser_js_1 = require("./browser");
12
10
  // =============================================================================
13
11
  // The ZipWriter class
14
12
  // Packs streamed data into an output zip stream
@@ -19,6 +17,10 @@ class ZipWriter extends events_1.default.EventEmitter {
19
17
  type: "nodebuffer",
20
18
  compression: "DEFLATE"
21
19
  }, options);
20
+ // Default compression level is 6 (good balance of speed and size)
21
+ // 0 = no compression, 9 = best compression
22
+ const level = this.options.compressionOptions?.level ?? 6;
23
+ this.compressionLevel = Math.max(0, Math.min(9, level));
22
24
  this.files = {};
23
25
  this.stream = new stream_buf_js_1.StreamBuf();
24
26
  this.finalized = false;
@@ -38,42 +40,36 @@ class ZipWriter extends events_1.default.EventEmitter {
38
40
  append(data, options) {
39
41
  let buffer;
40
42
  if (Object.prototype.hasOwnProperty.call(options, "base64") && options.base64) {
41
- // Use Buffer.from for efficient base64 decoding
43
+ // Decode base64 data - Buffer.from works in both Node.js and browser (via polyfill)
42
44
  const base64Data = typeof data === "string" ? data : data.toString();
43
- if (browser_js_1.isBrowser) {
44
- // Browser: use atob with optimized Uint8Array conversion
45
- const binaryString = atob(base64Data);
46
- const len = binaryString.length;
47
- buffer = new Uint8Array(len);
48
- // Use a single loop with cached length for better performance
49
- for (let i = 0; i < len; i++) {
50
- buffer[i] = binaryString.charCodeAt(i);
51
- }
52
- }
53
- else {
54
- // Node.js: use efficient Buffer.from
55
- buffer = Buffer.from(base64Data, "base64");
56
- }
45
+ buffer = Buffer.from(base64Data, "base64");
46
+ }
47
+ else if (typeof data === "string") {
48
+ // Convert string to Buffer - works in both environments
49
+ buffer = Buffer.from(data, "utf8");
50
+ }
51
+ else if (Buffer.isBuffer(data)) {
52
+ // Buffer extends Uint8Array, fflate can use it directly - no copy needed
53
+ buffer = data;
54
+ }
55
+ else if (ArrayBuffer.isView(data)) {
56
+ // Handle typed arrays - create view without copy
57
+ buffer = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
58
+ }
59
+ else if (data instanceof ArrayBuffer) {
60
+ // Handle ArrayBuffer directly
61
+ buffer = new Uint8Array(data);
57
62
  }
58
63
  else {
59
- if (typeof data === "string") {
60
- // Convert string to Uint8Array
61
- if (browser_js_1.isBrowser) {
62
- buffer = (0, browser_buffer_encode_js_1.stringToBuffer)(data);
63
- }
64
- else {
65
- buffer = Buffer.from(data, "utf8");
66
- }
67
- }
68
- else if (Buffer.isBuffer(data)) {
69
- buffer = new Uint8Array(data);
70
- }
71
- else {
72
- buffer = data;
73
- }
64
+ // Assume it's already a Uint8Array or compatible type
65
+ buffer = data;
74
66
  }
75
67
  // Add file to zip using streaming API
76
- const zipFile = new fflate_1.ZipPassThrough(options.name);
68
+ // Use ZipDeflate for compression or ZipPassThrough for no compression
69
+ const useCompression = this.options.compression !== "STORE";
70
+ const zipFile = useCompression
71
+ ? new fflate_1.ZipDeflate(options.name, { level: this.compressionLevel })
72
+ : new fflate_1.ZipPassThrough(options.name);
77
73
  this.zip.add(zipFile);
78
74
  zipFile.push(buffer, true); // true = final chunk
79
75
  }
@@ -11,7 +11,6 @@ const zip_stream_js_1 = require("../utils/zip-stream");
11
11
  const stream_buf_js_1 = require("../utils/stream-buf");
12
12
  const utils_js_1 = require("../utils/utils");
13
13
  const xml_stream_js_1 = require("../utils/xml-stream");
14
- const browser_buffer_decode_js_1 = require("../utils/browser-buffer-decode");
15
14
  const styles_xform_js_1 = require("./xform/style/styles-xform");
16
15
  const core_xform_js_1 = require("./xform/core/core-xform");
17
16
  const shared_strings_xform_js_1 = require("./xform/strings/shared-strings-xform");
@@ -377,7 +376,7 @@ class XLSX {
377
376
  readableObjectMode: true,
378
377
  writableObjectMode: true
379
378
  });
380
- const content = (0, browser_buffer_decode_js_1.bufferToString)(Buffer.from(entry.data));
379
+ const content = (0, utils_js_1.bufferToString)(Buffer.from(entry.data));
381
380
  stream.end(content);
382
381
  }
383
382
  let match;
@@ -1,3 +1,4 @@
1
1
  export { Workbook } from "./doc/workbook.js";
2
2
  export * from "./doc/enums.js";
3
3
  export * from "./types.js";
4
+ export * from "./utils/sheet-utils.js";
package/dist/esm/index.js CHANGED
@@ -18,3 +18,4 @@ export { DataValidations } from "./doc/data-validations.js";
18
18
  export * from "./doc/enums.js";
19
19
  // Export all type definitions
20
20
  export * from "./types.js";
21
+ export * from "./utils/sheet-utils.js";
@@ -3,7 +3,6 @@ import { EventEmitter } from "events";
3
3
  import { PassThrough, Readable } from "stream";
4
4
  import os from "os";
5
5
  import { join } from "path";
6
- import { Parse } from "unzipper";
7
6
  import { iterateStream } from "../../utils/iterate-stream.js";
8
7
  import { parseSax } from "../../utils/parse-sax.js";
9
8
  import { StylesXform } from "../../xlsx/xform/style/styles-xform.js";
@@ -11,6 +10,7 @@ import { WorkbookXform } from "../../xlsx/xform/book/workbook-xform.js";
11
10
  import { RelationshipsXform } from "../../xlsx/xform/core/relationships-xform.js";
12
11
  import { WorksheetReader } from "./worksheet-reader.js";
13
12
  import { HyperlinkReader } from "./hyperlink-reader.js";
13
+ import { createParse } from "../../utils/unzip/parse.js";
14
14
  class WorkbookReader extends EventEmitter {
15
15
  constructor(input, options = {}) {
16
16
  super();
@@ -70,7 +70,7 @@ class WorkbookReader extends EventEmitter {
70
70
  this.options = options;
71
71
  }
72
72
  const stream = (this.stream = this._getStream(input || this.input));
73
- const zip = Parse({ forceStream: true });
73
+ const zip = createParse({ forceStream: true });
74
74
  // Handle pipe errors to prevent unhandled rejection
75
75
  stream.on("error", (err) => {
76
76
  zip.emit("error", err);
@@ -1,5 +1,5 @@
1
1
  import fs from "fs";
2
- import { Zip, ZipPassThrough } from "fflate";
2
+ import { Zip, ZipDeflate } from "fflate";
3
3
  import { StreamBuf } from "../../utils/stream-buf.js";
4
4
  import { RelType } from "../../xlsx/rel-type.js";
5
5
  import { StylesXform } from "../../xlsx/xform/style/styles-xform.js";
@@ -30,6 +30,10 @@ class WorkbookWriter {
30
30
  this._worksheets = [];
31
31
  this.views = [];
32
32
  this.zipOptions = options.zip;
33
+ // Extract compression level from zip options (supports both zlib.level and compressionOptions.level)
34
+ // Default compression level is 6 (good balance of speed and size)
35
+ const level = options.zip?.zlib?.level ?? options.zip?.compressionOptions?.level ?? 6;
36
+ this.compressionLevel = Math.max(0, Math.min(9, level));
33
37
  this.media = [];
34
38
  this.commentRefs = [];
35
39
  // Create fflate Zip instance
@@ -61,8 +65,8 @@ class WorkbookWriter {
61
65
  }
62
66
  _openStream(path) {
63
67
  const stream = new StreamBuf({ bufSize: 65536, batch: true });
64
- // Create a ZipPassThrough for this file
65
- const zipFile = new ZipPassThrough(path);
68
+ // Create a ZipDeflate for this file with compression
69
+ const zipFile = new ZipDeflate(path, { level: this.compressionLevel });
66
70
  this.zip.add(zipFile);
67
71
  // Don't pause the stream - we need data events to flow
68
72
  // The original implementation used archiver which consumed the stream internally
@@ -81,8 +85,8 @@ class WorkbookWriter {
81
85
  return stream;
82
86
  }
83
87
  _addFile(data, name, base64) {
84
- // Helper method to add a file to the zip using fflate
85
- const zipFile = new ZipPassThrough(name);
88
+ // Helper method to add a file to the zip using fflate with compression
89
+ const zipFile = new ZipDeflate(name, { level: this.compressionLevel });
86
90
  this.zip.add(zipFile);
87
91
  let buffer;
88
92
  if (base64) {