@justybase/spreadsheet-tasks 1.3.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +25 -16
- package/browser/browser-spreadsheet.js +3037 -0
- package/browser/justybase-spreadsheet.min.js +36 -0
- package/dist/cjs/index.d.ts +399 -0
- package/dist/cjs/index.js +3944 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/index.js +3889 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/docs/API.md +8 -9
- package/docs/PACKAGING.md +32 -0
- package/docs/PUBLISHING.md +8 -1
- package/examples/basic-read.ts +1 -1
- package/examples/formats-verify.ts +1 -2
- package/examples/large-dataset.ts +1 -1
- package/package.json +28 -13
- package/dist/BiffReaderWriter.d.ts +0 -44
- package/dist/BiffReaderWriter.d.ts.map +0 -1
- package/dist/BiffReaderWriter.js +0 -282
- package/dist/BiffReaderWriter.js.map +0 -1
- package/dist/BigBuffer.d.ts +0 -24
- package/dist/BigBuffer.d.ts.map +0 -1
- package/dist/BigBuffer.js +0 -120
- package/dist/BigBuffer.js.map +0 -1
- package/dist/ExcelReaderAbstract.d.ts +0 -17
- package/dist/ExcelReaderAbstract.d.ts.map +0 -1
- package/dist/ExcelReaderAbstract.js +0 -25
- package/dist/ExcelReaderAbstract.js.map +0 -1
- package/dist/Formats.d.ts +0 -34
- package/dist/Formats.d.ts.map +0 -1
- package/dist/Formats.js +0 -48
- package/dist/Formats.js.map +0 -1
- package/dist/ReaderFactory.d.ts +0 -6
- package/dist/ReaderFactory.d.ts.map +0 -1
- package/dist/ReaderFactory.js +0 -56
- package/dist/ReaderFactory.js.map +0 -1
- package/dist/XlsbReader.d.ts +0 -24
- package/dist/XlsbReader.d.ts.map +0 -1
- package/dist/XlsbReader.js +0 -186
- package/dist/XlsbReader.js.map +0 -1
- package/dist/XlsbWriter.d.ts +0 -80
- package/dist/XlsbWriter.d.ts.map +0 -1
- package/dist/XlsbWriter.js +0 -964
- package/dist/XlsbWriter.js.map +0 -1
- package/dist/XlsxReader.d.ts +0 -30
- package/dist/XlsxReader.d.ts.map +0 -1
- package/dist/XlsxReader.js +0 -341
- package/dist/XlsxReader.js.map +0 -1
- package/dist/XlsxWriter.d.ts +0 -51
- package/dist/XlsxWriter.d.ts.map +0 -1
- package/dist/XlsxWriter.js +0 -632
- package/dist/XlsxWriter.js.map +0 -1
- package/dist/index.d.ts +0 -10
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -29
- package/dist/index.js.map +0 -1
package/dist/XlsxWriter.js
DELETED
|
@@ -1,632 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.XlsxWriter = void 0;
|
|
40
|
-
const fs = __importStar(require("fs"));
|
|
41
|
-
const archiver_1 = __importDefault(require("archiver"));
|
|
42
|
-
const stream_1 = require("stream");
|
|
43
|
-
const BigBuffer_1 = require("./BigBuffer");
|
|
44
|
-
const Formats_1 = require("./Formats");
|
|
45
|
-
const COLUMN_LETTERS = (() => {
|
|
46
|
-
const letters = [];
|
|
47
|
-
for (let i = 65; i < 91; i++) {
|
|
48
|
-
letters.push(String.fromCharCode(i));
|
|
49
|
-
}
|
|
50
|
-
const temp = [];
|
|
51
|
-
for (const p of letters) {
|
|
52
|
-
for (let i = 65; i < 91; i++) {
|
|
53
|
-
temp.push(p + String.fromCharCode(i));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
letters.push(...temp);
|
|
57
|
-
return letters;
|
|
58
|
-
})();
|
|
59
|
-
const INVALID_SHEET_NAME_CHARS = /[\\/*?[\]:]/g;
|
|
60
|
-
class XlsxWriter {
|
|
61
|
-
constructor(filePath) {
|
|
62
|
-
this.sheetCount = 0;
|
|
63
|
-
this.sheetList = [];
|
|
64
|
-
this.sstArray = [];
|
|
65
|
-
this.sstMap = new Map();
|
|
66
|
-
this.sstCntAll = 0;
|
|
67
|
-
this.colWidths = [];
|
|
68
|
-
this._autofilterIsOn = false;
|
|
69
|
-
// Format registry
|
|
70
|
-
this._formatRegistry = new Map();
|
|
71
|
-
this._formatXfMap = new Map();
|
|
72
|
-
this._nextNumfmtId = 165;
|
|
73
|
-
this._nextXfIndex = 4;
|
|
74
|
-
// Streaming state
|
|
75
|
-
this.currentSheetBuffer = null;
|
|
76
|
-
this.currentSheetRowNum = 0;
|
|
77
|
-
this.currentSheetStartCol = 0;
|
|
78
|
-
this.currentSheetEndCol = 0;
|
|
79
|
-
this.currentSheetDoAutofilter = false;
|
|
80
|
-
this.isStreaming = false;
|
|
81
|
-
this.currentColLetters = [];
|
|
82
|
-
this.output = fs.createWriteStream(filePath);
|
|
83
|
-
this.archive = (0, archiver_1.default)('zip');
|
|
84
|
-
this.archive.pipe(this.output);
|
|
85
|
-
this._oaEpoch = Date.UTC(1899, 11, 30);
|
|
86
|
-
}
|
|
87
|
-
_getColumnLetter(colIndex) {
|
|
88
|
-
return colIndex < COLUMN_LETTERS.length ? COLUMN_LETTERS[colIndex] : 'A';
|
|
89
|
-
}
|
|
90
|
-
_sanitizeSheetName(name) {
|
|
91
|
-
if (!name || typeof name !== 'string') {
|
|
92
|
-
return `Sheet${this.sheetCount + 1}`;
|
|
93
|
-
}
|
|
94
|
-
let sanitized = name.replace(INVALID_SHEET_NAME_CHARS, '_');
|
|
95
|
-
if (sanitized.length > 31) {
|
|
96
|
-
sanitized = sanitized.substring(0, 31);
|
|
97
|
-
}
|
|
98
|
-
if (sanitized.trim().length === 0) {
|
|
99
|
-
sanitized = `Sheet${this.sheetCount + 1}`;
|
|
100
|
-
}
|
|
101
|
-
return sanitized;
|
|
102
|
-
}
|
|
103
|
-
_escapeSheetNameForXml(name) {
|
|
104
|
-
return name
|
|
105
|
-
.replace(/&/g, '&')
|
|
106
|
-
.replace(/</g, '<')
|
|
107
|
-
.replace(/>/g, '>')
|
|
108
|
-
.replace(/"/g, '"')
|
|
109
|
-
.replace(/'/g, ''');
|
|
110
|
-
}
|
|
111
|
-
_formatSheetNameForFormula(name) {
|
|
112
|
-
if (/[\s\-+=()!@#$%^&]/.test(name) || /^[0-9]/.test(name)) {
|
|
113
|
-
const escaped = name.replace(/'/g, "''");
|
|
114
|
-
return `'${escaped}'`;
|
|
115
|
-
}
|
|
116
|
-
return name;
|
|
117
|
-
}
|
|
118
|
-
addSheet(sheetName, hidden = false) {
|
|
119
|
-
const sanitizedName = this._sanitizeSheetName(sheetName);
|
|
120
|
-
this.sheetCount++;
|
|
121
|
-
const rId = `rId${this.sheetCount}`;
|
|
122
|
-
const sheetFileName = `sheet${this.sheetCount}.xml`;
|
|
123
|
-
this.sheetList.push({
|
|
124
|
-
name: sanitizedName,
|
|
125
|
-
pathInArchive: `xl/worksheets/${sheetFileName}`,
|
|
126
|
-
hidden: hidden,
|
|
127
|
-
nameInArchive: sheetFileName,
|
|
128
|
-
sheetId: this.sheetCount,
|
|
129
|
-
rId: rId,
|
|
130
|
-
filterHeaderRange: null
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
_needsEscape(str) {
|
|
134
|
-
for (let i = 0; i < str.length; i++) {
|
|
135
|
-
const c = str.charCodeAt(i);
|
|
136
|
-
if (c === 38 || c === 60 || c === 62 || c === 34 || c === 39 ||
|
|
137
|
-
(c >= 0 && c <= 8) || c === 11 || c === 12 || (c >= 14 && c <= 31)) {
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
_escape(str) {
|
|
144
|
-
if (typeof str !== 'string')
|
|
145
|
-
return str;
|
|
146
|
-
if (!this._needsEscape(str))
|
|
147
|
-
return str;
|
|
148
|
-
return str.replace(/&/g, '&')
|
|
149
|
-
.replace(/</g, '<')
|
|
150
|
-
.replace(/>/g, '>')
|
|
151
|
-
.replace(/"/g, '"')
|
|
152
|
-
.replace(/'/g, ''')
|
|
153
|
-
// eslint-disable-next-line no-control-regex
|
|
154
|
-
.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g, '');
|
|
155
|
-
}
|
|
156
|
-
startSheet(sheetName, columnCount, headers, options = {}) {
|
|
157
|
-
if (this.isStreaming) {
|
|
158
|
-
throw new Error('Already in streaming mode. Call endSheet() first.');
|
|
159
|
-
}
|
|
160
|
-
const { hidden = false, doAutofilter = true, sampleRows } = options;
|
|
161
|
-
this.addSheet(sheetName, hidden);
|
|
162
|
-
this.isStreaming = true;
|
|
163
|
-
this.currentSheetBuffer = new BigBuffer_1.BigBuffer();
|
|
164
|
-
this.currentSheetRowNum = 0;
|
|
165
|
-
this.currentSheetStartCol = 0;
|
|
166
|
-
this.currentSheetEndCol = columnCount;
|
|
167
|
-
this.currentSheetDoAutofilter = doAutofilter && headers !== undefined;
|
|
168
|
-
const bigBuf = this.currentSheetBuffer;
|
|
169
|
-
this.colWidths = new Array(columnCount).fill(-1.0);
|
|
170
|
-
const colLetters = new Array(columnCount);
|
|
171
|
-
for (let i = 0; i < columnCount; i++) {
|
|
172
|
-
colLetters[i] = this._getColumnLetter(i);
|
|
173
|
-
}
|
|
174
|
-
this.currentColLetters = colLetters;
|
|
175
|
-
if (headers) {
|
|
176
|
-
for (let i = 0; i < columnCount; i++) {
|
|
177
|
-
const len = headers[i] ? headers[i].length + 1 : 0;
|
|
178
|
-
let width = 1.25 * len + 2;
|
|
179
|
-
if (width > 80)
|
|
180
|
-
width = 80;
|
|
181
|
-
if (this.colWidths[i] < width)
|
|
182
|
-
this.colWidths[i] = width;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (sampleRows) {
|
|
186
|
-
for (let r = 0; r < Math.min(sampleRows.length, 100); r++) {
|
|
187
|
-
const row = sampleRows[r];
|
|
188
|
-
for (let c = 0; c < row.length; c++) {
|
|
189
|
-
const raw = row[c];
|
|
190
|
-
if (raw === null || raw === undefined)
|
|
191
|
-
continue;
|
|
192
|
-
const val = (0, Formats_1.isFormattedCell)(raw) ? raw.value : raw;
|
|
193
|
-
const len = val instanceof Date ? 20 : val.toString().length + 1;
|
|
194
|
-
let width = 1.25 * len + 2;
|
|
195
|
-
if (width > 80)
|
|
196
|
-
width = 80;
|
|
197
|
-
if (this.colWidths[c] < width)
|
|
198
|
-
this.colWidths[c] = width;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
bigBuf.writeString('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
|
|
203
|
-
bigBuf.writeString('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
|
|
204
|
-
// Dimension - just A1 since we don't know row count in advance
|
|
205
|
-
bigBuf.writeString('<dimension ref="A1"/>');
|
|
206
|
-
const isFirstSheet = this.sheetCount === 1;
|
|
207
|
-
if (headers) {
|
|
208
|
-
if (isFirstSheet) {
|
|
209
|
-
bigBuf.writeString('<sheetViews><sheetView tabSelected="1" workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen" /><selection pane="bottomLeft" /></sheetView></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
bigBuf.writeString('<sheetViews><sheetView workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen" /><selection pane="bottomLeft" /></sheetView></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
if (isFirstSheet) {
|
|
217
|
-
bigBuf.writeString('<sheetViews><sheetView tabSelected="1" workbookViewId="0"/></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
bigBuf.writeString('<sheetViews><sheetView workbookViewId="0"/></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
bigBuf.writeString('<cols>');
|
|
224
|
-
for (let i = 0; i < columnCount; i++) {
|
|
225
|
-
const width = this.colWidths[i] > 0 ? this.colWidths[i] : 10;
|
|
226
|
-
bigBuf.writeString(`<col min="${i + 1}" max="${i + 1}" width="${width}" bestFit="1" customWidth="1" />`);
|
|
227
|
-
}
|
|
228
|
-
bigBuf.writeString('</cols><sheetData>');
|
|
229
|
-
if (headers) {
|
|
230
|
-
this.currentSheetRowNum++;
|
|
231
|
-
bigBuf.writeString(`<row r="${this.currentSheetRowNum}">`);
|
|
232
|
-
for (let c = 0; c < headers.length; c++) {
|
|
233
|
-
this._writeStringCell(bigBuf, headers[c], colLetters[c], this.currentSheetRowNum, 3);
|
|
234
|
-
}
|
|
235
|
-
bigBuf.writeString('</row>');
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
writeRow(row) {
|
|
239
|
-
if (!this.isStreaming || !this.currentSheetBuffer) {
|
|
240
|
-
throw new Error('Not in streaming mode. Call startSheet() first.');
|
|
241
|
-
}
|
|
242
|
-
if (row.length !== this.currentSheetEndCol - this.currentSheetStartCol) {
|
|
243
|
-
throw new Error(`Row length mismatch. Expected ${this.currentSheetEndCol - this.currentSheetStartCol} columns, got ${row.length}`);
|
|
244
|
-
}
|
|
245
|
-
const bigBuf = this.currentSheetBuffer;
|
|
246
|
-
this.currentSheetRowNum++;
|
|
247
|
-
bigBuf.writeString(`<row r="${this.currentSheetRowNum}">`);
|
|
248
|
-
for (let c = 0; c < row.length; c++) {
|
|
249
|
-
const raw = row[c];
|
|
250
|
-
if (raw === null || raw === undefined)
|
|
251
|
-
continue;
|
|
252
|
-
const fmtString = (0, Formats_1.getFormat)(raw);
|
|
253
|
-
const val = fmtString !== null ? (0, Formats_1.unwrapCell)(raw) : raw;
|
|
254
|
-
const xfIdx = fmtString !== null ? this._registerFormat(fmtString) : -1;
|
|
255
|
-
const styleAttr = xfIdx >= 0 ? ` s="${xfIdx}"` : '';
|
|
256
|
-
const colRef = this.currentColLetters[c];
|
|
257
|
-
if (typeof val === 'number') {
|
|
258
|
-
if (Number.isFinite(val)) {
|
|
259
|
-
bigBuf.writeString(`<c r="${colRef}${this.currentSheetRowNum}"${styleAttr}><v>${val}</v></c>`);
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, this.currentSheetRowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
else if (typeof val === 'bigint') {
|
|
266
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, this.currentSheetRowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
267
|
-
}
|
|
268
|
-
else if (typeof val === 'boolean') {
|
|
269
|
-
bigBuf.writeString(`<c r="${colRef}${this.currentSheetRowNum}" t="b"${styleAttr}><v>${val ? 1 : 0}</v></c>`);
|
|
270
|
-
}
|
|
271
|
-
else if (val instanceof Date) {
|
|
272
|
-
const oaDate = this._toOADate(val);
|
|
273
|
-
if (Number.isFinite(oaDate)) {
|
|
274
|
-
const finalStyle = xfIdx >= 0 ? xfIdx : 1;
|
|
275
|
-
bigBuf.writeString(`<c r="${colRef}${this.currentSheetRowNum}" s="${finalStyle}"><v>${oaDate}</v></c>`);
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, this.currentSheetRowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, this.currentSheetRowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
bigBuf.writeString('</row>');
|
|
286
|
-
}
|
|
287
|
-
endSheet() {
|
|
288
|
-
if (!this.isStreaming || !this.currentSheetBuffer) {
|
|
289
|
-
throw new Error('Not in streaming mode. Call startSheet() first.');
|
|
290
|
-
}
|
|
291
|
-
const bigBuf = this.currentSheetBuffer;
|
|
292
|
-
bigBuf.writeString('</sheetData>');
|
|
293
|
-
if (this.currentSheetDoAutofilter && this.currentSheetEndCol > 0) {
|
|
294
|
-
this._autofilterIsOn = true;
|
|
295
|
-
const filterRef = `A1:${this.currentColLetters[this.currentSheetEndCol - 1]}${this.currentSheetRowNum}`;
|
|
296
|
-
bigBuf.writeString(`<autoFilter ref="${filterRef}"/>`);
|
|
297
|
-
const sheet = this.sheetList[this.sheetCount - 1];
|
|
298
|
-
const formulaSheetName = this._formatSheetNameForFormula(sheet.name);
|
|
299
|
-
sheet.filterHeaderRange = `${formulaSheetName}!$A$1:$${this.currentColLetters[this.currentSheetEndCol - 1]}$${this.currentSheetRowNum}`;
|
|
300
|
-
}
|
|
301
|
-
bigBuf.writeString('</worksheet>');
|
|
302
|
-
this.archive.append(stream_1.Readable.from(bigBuf.getChunks()), {
|
|
303
|
-
name: this.sheetList[this.sheetCount - 1].pathInArchive
|
|
304
|
-
});
|
|
305
|
-
// Reset streaming state
|
|
306
|
-
this.isStreaming = false;
|
|
307
|
-
this.currentSheetBuffer = null;
|
|
308
|
-
this.currentSheetRowNum = 0;
|
|
309
|
-
this.currentSheetStartCol = 0;
|
|
310
|
-
this.currentSheetEndCol = 0;
|
|
311
|
-
this.currentSheetDoAutofilter = false;
|
|
312
|
-
this.currentColLetters = [];
|
|
313
|
-
}
|
|
314
|
-
writeSheet(rows, headers = null, doAutofilter = true) {
|
|
315
|
-
const bigBuf = new BigBuffer_1.BigBuffer();
|
|
316
|
-
let columnCount = 0;
|
|
317
|
-
if (rows.length > 0) {
|
|
318
|
-
columnCount = rows[0].length;
|
|
319
|
-
}
|
|
320
|
-
else if (headers) {
|
|
321
|
-
columnCount = headers.length;
|
|
322
|
-
}
|
|
323
|
-
this.colWidths = new Array(columnCount).fill(-1.0);
|
|
324
|
-
const colLetters = new Array(columnCount);
|
|
325
|
-
for (let i = 0; i < columnCount; i++) {
|
|
326
|
-
colLetters[i] = this._getColumnLetter(i);
|
|
327
|
-
}
|
|
328
|
-
if (headers) {
|
|
329
|
-
for (let i = 0; i < columnCount; i++) {
|
|
330
|
-
const len = headers[i] ? headers[i].length + 1 : 0;
|
|
331
|
-
let width = 1.25 * len + 2;
|
|
332
|
-
if (width > 80)
|
|
333
|
-
width = 80;
|
|
334
|
-
if (this.colWidths[i] < width)
|
|
335
|
-
this.colWidths[i] = width;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
for (let r = 0; r < Math.min(rows.length, 100); r++) {
|
|
339
|
-
const row = rows[r];
|
|
340
|
-
for (let c = 0; c < row.length; c++) {
|
|
341
|
-
const raw = row[c];
|
|
342
|
-
if (raw === null || raw === undefined)
|
|
343
|
-
continue;
|
|
344
|
-
const val = (0, Formats_1.isFormattedCell)(raw) ? raw.value : raw;
|
|
345
|
-
const len = val instanceof Date ? 20 : val.toString().length + 1;
|
|
346
|
-
let width = 1.25 * len + 2;
|
|
347
|
-
if (width > 80)
|
|
348
|
-
width = 80;
|
|
349
|
-
if (this.colWidths[c] < width)
|
|
350
|
-
this.colWidths[c] = width;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
bigBuf.writeString('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
|
|
354
|
-
bigBuf.writeString('<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
|
|
355
|
-
const totalRows = rows.length + (headers ? 1 : 0);
|
|
356
|
-
if (totalRows > 0 && columnCount > 0) {
|
|
357
|
-
bigBuf.writeString(`<dimension ref="A1:${colLetters[columnCount - 1]}${totalRows}"/>`);
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
bigBuf.writeString('<dimension ref="A1"/>');
|
|
361
|
-
}
|
|
362
|
-
const isFirstSheet = this.sheetCount === 1;
|
|
363
|
-
if (headers) {
|
|
364
|
-
if (isFirstSheet) {
|
|
365
|
-
bigBuf.writeString('<sheetViews><sheetView tabSelected="1" workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen" /><selection pane="bottomLeft" /></sheetView></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
bigBuf.writeString('<sheetViews><sheetView workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen" /><selection pane="bottomLeft" /></sheetView></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
if (isFirstSheet) {
|
|
373
|
-
bigBuf.writeString('<sheetViews><sheetView tabSelected="1" workbookViewId="0"/></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
374
|
-
}
|
|
375
|
-
else {
|
|
376
|
-
bigBuf.writeString('<sheetViews><sheetView workbookViewId="0"/></sheetViews><sheetFormatPr defaultRowHeight="15"/>');
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
bigBuf.writeString('<cols>');
|
|
380
|
-
for (let i = 0; i < columnCount; i++) {
|
|
381
|
-
const width = this.colWidths[i] > 0 ? this.colWidths[i] : 10;
|
|
382
|
-
bigBuf.writeString(`<col min="${i + 1}" max="${i + 1}" width="${width}" bestFit="1" customWidth="1" />`);
|
|
383
|
-
}
|
|
384
|
-
bigBuf.writeString('</cols><sheetData>');
|
|
385
|
-
let rowNum = 0;
|
|
386
|
-
if (headers) {
|
|
387
|
-
rowNum++;
|
|
388
|
-
bigBuf.writeString(`<row r="${rowNum}">`);
|
|
389
|
-
for (let c = 0; c < headers.length; c++) {
|
|
390
|
-
this._writeStringCell(bigBuf, headers[c], colLetters[c], rowNum, 3);
|
|
391
|
-
}
|
|
392
|
-
bigBuf.writeString('</row>');
|
|
393
|
-
}
|
|
394
|
-
for (let r = 0; r < rows.length; r++) {
|
|
395
|
-
rowNum++;
|
|
396
|
-
bigBuf.writeString(`<row r="${rowNum}">`);
|
|
397
|
-
const row = rows[r];
|
|
398
|
-
for (let c = 0; c < row.length; c++) {
|
|
399
|
-
const raw = row[c];
|
|
400
|
-
if (raw === null || raw === undefined)
|
|
401
|
-
continue;
|
|
402
|
-
const fmtString = (0, Formats_1.getFormat)(raw);
|
|
403
|
-
const val = fmtString !== null ? (0, Formats_1.unwrapCell)(raw) : raw;
|
|
404
|
-
const xfIdx = fmtString !== null ? this._registerFormat(fmtString) : -1;
|
|
405
|
-
const styleAttr = xfIdx >= 0 ? ` s="${xfIdx}"` : '';
|
|
406
|
-
const colRef = colLetters[c];
|
|
407
|
-
if (typeof val === 'number') {
|
|
408
|
-
if (Number.isFinite(val)) {
|
|
409
|
-
bigBuf.writeString(`<c r="${colRef}${rowNum}"${styleAttr}><v>${val}</v></c>`);
|
|
410
|
-
}
|
|
411
|
-
else {
|
|
412
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, rowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
else if (typeof val === 'bigint') {
|
|
416
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, rowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
417
|
-
}
|
|
418
|
-
else if (typeof val === 'boolean') {
|
|
419
|
-
bigBuf.writeString(`<c r="${colRef}${rowNum}" t="b"${styleAttr}><v>${val ? 1 : 0}</v></c>`);
|
|
420
|
-
}
|
|
421
|
-
else if (val instanceof Date) {
|
|
422
|
-
const oaDate = this._toOADate(val);
|
|
423
|
-
if (Number.isFinite(oaDate)) {
|
|
424
|
-
const finalStyle = xfIdx >= 0 ? xfIdx : 1;
|
|
425
|
-
bigBuf.writeString(`<c r="${colRef}${rowNum}" s="${finalStyle}"><v>${oaDate}</v></c>`);
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, rowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
else {
|
|
432
|
-
this._writeStringCell(bigBuf, val.toString(), colRef, rowNum, xfIdx >= 0 ? xfIdx : undefined);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
bigBuf.writeString('</row>');
|
|
436
|
-
}
|
|
437
|
-
bigBuf.writeString('</sheetData>');
|
|
438
|
-
if (doAutofilter && headers && columnCount > 0) {
|
|
439
|
-
this._autofilterIsOn = true;
|
|
440
|
-
const filterRef = `A1:${colLetters[columnCount - 1]}${totalRows}`;
|
|
441
|
-
bigBuf.writeString(`<autoFilter ref="${filterRef}"/>`);
|
|
442
|
-
const sheet = this.sheetList[this.sheetCount - 1];
|
|
443
|
-
const formulaSheetName = this._formatSheetNameForFormula(sheet.name);
|
|
444
|
-
sheet.filterHeaderRange = `${formulaSheetName}!$A$1:$${colLetters[columnCount - 1]}$${totalRows}`;
|
|
445
|
-
}
|
|
446
|
-
bigBuf.writeString('</worksheet>');
|
|
447
|
-
this.archive.append(stream_1.Readable.from(bigBuf.getChunks()), {
|
|
448
|
-
name: this.sheetList[this.sheetCount - 1].pathInArchive
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
_writeStringCell(bigBuf, val, colRef, rowNum, styleOverride) {
|
|
452
|
-
let index = this.sstMap.get(val);
|
|
453
|
-
if (index === undefined) {
|
|
454
|
-
index = this.sstArray.length;
|
|
455
|
-
this.sstArray.push(val);
|
|
456
|
-
this.sstMap.set(val, index);
|
|
457
|
-
}
|
|
458
|
-
this.sstCntAll++;
|
|
459
|
-
const styleAttr = styleOverride !== undefined ? ` s="${styleOverride}"` : '';
|
|
460
|
-
bigBuf.writeString(`<c r="${colRef}${rowNum}" t="s"${styleAttr}><v>${index}</v></c>`);
|
|
461
|
-
}
|
|
462
|
-
_registerFormat(fmtString) {
|
|
463
|
-
if (this._formatXfMap.has(fmtString)) {
|
|
464
|
-
return this._formatXfMap.get(fmtString);
|
|
465
|
-
}
|
|
466
|
-
const numfmtId = this._nextNumfmtId++;
|
|
467
|
-
this._formatRegistry.set(fmtString, numfmtId);
|
|
468
|
-
const xfIndex = this._nextXfIndex++;
|
|
469
|
-
this._formatXfMap.set(fmtString, xfIndex);
|
|
470
|
-
return xfIndex;
|
|
471
|
-
}
|
|
472
|
-
_toOADate(date) {
|
|
473
|
-
// Use UTC time to avoid timezone conversion issues
|
|
474
|
-
return (date.getTime() - this._oaEpoch) / 86400000;
|
|
475
|
-
}
|
|
476
|
-
_getDateWidth(_date) {
|
|
477
|
-
return 19; // "YYYY-MM-DD HH:MM:SS" ≈ 19 chars
|
|
478
|
-
}
|
|
479
|
-
finalize() {
|
|
480
|
-
return new Promise((resolve, reject) => {
|
|
481
|
-
try {
|
|
482
|
-
this._writeSharedStrings();
|
|
483
|
-
this._writeStyles();
|
|
484
|
-
this._writeWorkbook();
|
|
485
|
-
this._writeContentTypes();
|
|
486
|
-
this._writeRels();
|
|
487
|
-
this.output.on('close', () => {
|
|
488
|
-
resolve();
|
|
489
|
-
});
|
|
490
|
-
this.archive.on('error', (err) => {
|
|
491
|
-
reject(err);
|
|
492
|
-
});
|
|
493
|
-
this.archive.finalize();
|
|
494
|
-
}
|
|
495
|
-
catch (err) {
|
|
496
|
-
reject(err);
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
_writeSharedStrings() {
|
|
501
|
-
const bigBuf = new BigBuffer_1.BigBuffer();
|
|
502
|
-
bigBuf.writeString('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>');
|
|
503
|
-
bigBuf.writeString(`<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="${this.sstCntAll}" uniqueCount="${this.sstArray.length}">`);
|
|
504
|
-
for (let i = 0; i < this.sstArray.length; i++) {
|
|
505
|
-
const txt = this.sstArray[i];
|
|
506
|
-
const cleanTxt = this._escape(txt);
|
|
507
|
-
if (cleanTxt.length > 0 && (cleanTxt[0] === ' ' || cleanTxt[cleanTxt.length - 1] === ' ' || /[\t\n\r]/.test(cleanTxt))) {
|
|
508
|
-
bigBuf.writeString(`<si><t xml:space="preserve">${cleanTxt}</t></si>`);
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
bigBuf.writeString(`<si><t>${cleanTxt}</t></si>`);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
bigBuf.writeString('</sst>');
|
|
515
|
-
this.archive.append(stream_1.Readable.from(bigBuf.getChunks()), { name: 'xl/sharedStrings.xml' });
|
|
516
|
-
}
|
|
517
|
-
_writeStyles() {
|
|
518
|
-
let numFmts = '';
|
|
519
|
-
let numFmtCount = 0;
|
|
520
|
-
const xfEntries = [];
|
|
521
|
-
xfEntries.push('<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>');
|
|
522
|
-
xfEntries.push('<xf numFmtId="14" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>');
|
|
523
|
-
xfEntries.push('<xf numFmtId="22" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>');
|
|
524
|
-
xfEntries.push('<xf numFmtId="0" fontId="1" fillId="0" borderId="0" xfId="0" applyFont="1"/>');
|
|
525
|
-
for (const [fmtString, numfmtId] of this._formatRegistry) {
|
|
526
|
-
const escapedFmt = fmtString
|
|
527
|
-
.replace(/&/g, '&')
|
|
528
|
-
.replace(/</g, '<')
|
|
529
|
-
.replace(/>/g, '>')
|
|
530
|
-
.replace(/"/g, '"')
|
|
531
|
-
.replace(/'/g, ''');
|
|
532
|
-
numFmts += `<numFmt numFmtId="${numfmtId}" formatCode="${escapedFmt}"/>`;
|
|
533
|
-
numFmtCount++;
|
|
534
|
-
}
|
|
535
|
-
const sortedFormats = [...this._formatXfMap.entries()].sort((a, b) => a[1] - b[1]);
|
|
536
|
-
for (const [fmtString] of sortedFormats) {
|
|
537
|
-
const numfmtId = this._formatRegistry.get(fmtString);
|
|
538
|
-
xfEntries.push(`<xf numFmtId="${numfmtId}" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>`);
|
|
539
|
-
}
|
|
540
|
-
const totalXf = xfEntries.length;
|
|
541
|
-
const numFmtsSection = numFmtCount > 0 ? `<numFmts count="${numFmtCount}">${numFmts}</numFmts>` : '';
|
|
542
|
-
const styles = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
543
|
-
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
|
544
|
-
${numFmtsSection}
|
|
545
|
-
<fonts count="2">
|
|
546
|
-
<font><sz val="11"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font>
|
|
547
|
-
<font><b/><sz val="11"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font>
|
|
548
|
-
</fonts>
|
|
549
|
-
<fills count="2">
|
|
550
|
-
<fill><patternFill patternType="none"/></fill>
|
|
551
|
-
<fill><patternFill patternType="gray125"/></fill>
|
|
552
|
-
</fills>
|
|
553
|
-
<borders count="1">
|
|
554
|
-
<border><left/><right/><top/><bottom/><diagonal/></border>
|
|
555
|
-
</borders>
|
|
556
|
-
<cellStyleXfs count="1">
|
|
557
|
-
<xf numFmtId="0" fontId="0" fillId="0" borderId="0"/>
|
|
558
|
-
</cellStyleXfs>
|
|
559
|
-
<cellXfs count="${totalXf}">
|
|
560
|
-
${xfEntries.join('\n')}
|
|
561
|
-
</cellXfs>
|
|
562
|
-
<cellStyles count="1">
|
|
563
|
-
<cellStyle name="Normal" xfId="0" builtinId="0"/>
|
|
564
|
-
</cellStyles>
|
|
565
|
-
<dxfs count="0"/>
|
|
566
|
-
<tableStyles count="0" defaultTableStyle="TableStyleMedium2" defaultPivotStyle="PivotStyleLight16"/>
|
|
567
|
-
</styleSheet>`;
|
|
568
|
-
this.archive.append(styles, { name: 'xl/styles.xml' });
|
|
569
|
-
}
|
|
570
|
-
_writeWorkbook() {
|
|
571
|
-
let xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
572
|
-
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
|
573
|
-
<fileVersion appName="xl" lastEdited="4" lowestEdited="4" rupBuild="4505"/>
|
|
574
|
-
<workbookPr defaultThemeVersion="124226"/>
|
|
575
|
-
<bookViews><workbookView xWindow="240" yWindow="15" windowWidth="16095" windowHeight="9660"/></bookViews>
|
|
576
|
-
<sheets>`;
|
|
577
|
-
for (const sheet of this.sheetList) {
|
|
578
|
-
const state = sheet.hidden ? ' state="hidden"' : '';
|
|
579
|
-
const escapedName = this._escapeSheetNameForXml(sheet.name);
|
|
580
|
-
xml += `<sheet name="${escapedName}" sheetId="${sheet.sheetId}"${state} r:id="${sheet.rId}"/>`;
|
|
581
|
-
}
|
|
582
|
-
xml += `</sheets>`;
|
|
583
|
-
if (this._autofilterIsOn) {
|
|
584
|
-
xml += '<definedNames>';
|
|
585
|
-
for (const sheet of this.sheetList) {
|
|
586
|
-
if (sheet.filterHeaderRange) {
|
|
587
|
-
const localSheetId = sheet.sheetId - 1;
|
|
588
|
-
const escapedRange = this._escape(sheet.filterHeaderRange);
|
|
589
|
-
xml += `<definedName name="_xlnm._FilterDatabase" localSheetId="${localSheetId}" hidden="1">${escapedRange}</definedName>`;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
xml += '</definedNames>';
|
|
593
|
-
}
|
|
594
|
-
xml += '<calcPr calcId="124519" fullCalcOnLoad="1"/>';
|
|
595
|
-
xml += `</workbook>`;
|
|
596
|
-
this.archive.append(xml, { name: 'xl/workbook.xml' });
|
|
597
|
-
}
|
|
598
|
-
_writeContentTypes() {
|
|
599
|
-
let xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
600
|
-
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
601
|
-
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
602
|
-
<Default Extension="xml" ContentType="application/xml"/>
|
|
603
|
-
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
|
|
604
|
-
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
|
|
605
|
-
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>`;
|
|
606
|
-
for (const sheet of this.sheetList) {
|
|
607
|
-
xml += `<Override PartName="/${sheet.pathInArchive}" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`;
|
|
608
|
-
}
|
|
609
|
-
xml += `</Types>`;
|
|
610
|
-
this.archive.append(xml, { name: '[Content_Types].xml' });
|
|
611
|
-
}
|
|
612
|
-
_writeRels() {
|
|
613
|
-
const globalRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
614
|
-
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
615
|
-
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
|
|
616
|
-
</Relationships>`;
|
|
617
|
-
this.archive.append(globalRels, { name: '_rels/.rels' });
|
|
618
|
-
let wbRels = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
619
|
-
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">`;
|
|
620
|
-
for (const sheet of this.sheetList) {
|
|
621
|
-
wbRels += `<Relationship Id="${sheet.rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/${sheet.nameInArchive}"/>`;
|
|
622
|
-
}
|
|
623
|
-
let nextId = this.sheetList.length + 1;
|
|
624
|
-
wbRels += `<Relationship Id="rId${nextId++}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>`;
|
|
625
|
-
wbRels += `<Relationship Id="rId${nextId++}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>`;
|
|
626
|
-
wbRels += `</Relationships>`;
|
|
627
|
-
this.archive.append(wbRels, { name: 'xl/_rels/workbook.xml.rels' });
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
exports.XlsxWriter = XlsxWriter;
|
|
631
|
-
exports.default = XlsxWriter;
|
|
632
|
-
//# sourceMappingURL=XlsxWriter.js.map
|