@simplysm/excel 13.0.78 → 13.0.81

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 (2) hide show
  1. package/package.json +4 -3
  2. package/README.md +0 -583
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/excel",
3
- "version": "13.0.78",
3
+ "version": "13.0.81",
4
4
  "description": "Excel file processing library",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -15,12 +15,13 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "src",
18
- "tests"
18
+ "tests",
19
+ "docs"
19
20
  ],
20
21
  "sideEffects": false,
21
22
  "dependencies": {
22
23
  "mime": "^4.1.0",
23
24
  "zod": "^4.3.6",
24
- "@simplysm/core-common": "13.0.78"
25
+ "@simplysm/core-common": "13.0.81"
25
26
  }
26
27
  }
package/README.md DELETED
@@ -1,583 +0,0 @@
1
- # @simplysm/excel
2
-
3
- Excel file processing library for reading, writing, and manipulating `.xlsx` files.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- pnpm add @simplysm/excel
9
- ```
10
-
11
- ## Quick Example
12
-
13
- ```typescript
14
- import { ExcelWorkbook } from "@simplysm/excel";
15
-
16
- // Read an existing file
17
- const bytes: Uint8Array = /* file bytes */;
18
- await using wb = new ExcelWorkbook(bytes);
19
- const ws = await wb.getWorksheet(0);
20
- const table = await ws.getDataTable(); // [{ Name: "Alice", Age: 30 }, ...]
21
-
22
- // Create a new file
23
- await using wb2 = new ExcelWorkbook();
24
- const ws2 = await wb2.addWorksheet("Sheet1");
25
- await ws2.setRecords([{ Name: "Alice", Age: 30 }]);
26
- const output = await wb2.toBytes();
27
- ```
28
-
29
- ---
30
-
31
- ## Types and Utilities
32
-
33
- ### `ExcelValueType`
34
-
35
- Union of all supported cell value types.
36
-
37
- ```typescript
38
- import { ExcelValueType } from "@simplysm/excel";
39
-
40
- type ExcelValueType = number | string | DateOnly | DateTime | Time | boolean | undefined;
41
- ```
42
-
43
- ### `ExcelNumberFormat`
44
-
45
- Named number format for a cell.
46
-
47
- ```typescript
48
- import { ExcelNumberFormat } from "@simplysm/excel";
49
-
50
- type ExcelNumberFormat = "number" | "string" | "DateOnly" | "DateTime" | "Time";
51
- ```
52
-
53
- ### `ExcelCellType`
54
-
55
- Raw Excel cell type code stored in the XML.
56
-
57
- ```typescript
58
- import { ExcelCellType } from "@simplysm/excel";
59
-
60
- // "s" - shared string
61
- // "b" - boolean
62
- // "str" - formula result string
63
- // "n" - number
64
- // "inlineStr" - inline string (rich text)
65
- // "e" - error
66
- type ExcelCellType = "s" | "b" | "str" | "n" | "inlineStr" | "e";
67
- ```
68
-
69
- ### `ExcelAddressPoint`
70
-
71
- A 0-based row/column coordinate pair.
72
-
73
- ```typescript
74
- import { ExcelAddressPoint } from "@simplysm/excel";
75
-
76
- interface ExcelAddressPoint {
77
- r: number; // 0-based row index
78
- c: number; // 0-based column index
79
- }
80
- ```
81
-
82
- ### `ExcelAddressRangePoint`
83
-
84
- A range defined by start and end `ExcelAddressPoint` values.
85
-
86
- ```typescript
87
- import { ExcelAddressRangePoint } from "@simplysm/excel";
88
-
89
- interface ExcelAddressRangePoint {
90
- s: ExcelAddressPoint; // start (top-left)
91
- e: ExcelAddressPoint; // end (bottom-right)
92
- }
93
- ```
94
-
95
- ### `ExcelStyleOptions`
96
-
97
- Options for `ExcelCell.setStyle()`.
98
-
99
- ```typescript
100
- import { ExcelStyleOptions } from "@simplysm/excel";
101
-
102
- interface ExcelStyleOptions {
103
- background?: string; // ARGB 8-digit hex, e.g. "FFFF0000" (red)
104
- border?: ExcelBorderPosition[]; // Border sides to draw
105
- horizontalAlign?: ExcelHorizontalAlign;
106
- verticalAlign?: ExcelVerticalAlign;
107
- numberFormat?: ExcelNumberFormat;
108
- }
109
- ```
110
-
111
- ### `ExcelBorderPosition`
112
-
113
- ```typescript
114
- import { ExcelBorderPosition } from "@simplysm/excel";
115
-
116
- type ExcelBorderPosition = "left" | "right" | "top" | "bottom";
117
- ```
118
-
119
- ### `ExcelHorizontalAlign`
120
-
121
- ```typescript
122
- import { ExcelHorizontalAlign } from "@simplysm/excel";
123
-
124
- type ExcelHorizontalAlign = "center" | "left" | "right";
125
- ```
126
-
127
- ### `ExcelVerticalAlign`
128
-
129
- ```typescript
130
- import { ExcelVerticalAlign } from "@simplysm/excel";
131
-
132
- type ExcelVerticalAlign = "center" | "top" | "bottom";
133
- ```
134
-
135
- ### XML Data Types
136
-
137
- These interfaces represent the raw XML structures parsed from the `.xlsx` ZIP package. Exported for advanced use cases (e.g., directly reading the parsed XML tree).
138
-
139
- ```typescript
140
- import {
141
- ExcelXmlContentTypeData,
142
- ExcelXmlRelationshipData,
143
- ExcelRelationshipData,
144
- ExcelXmlWorkbookData,
145
- ExcelXmlWorksheetData,
146
- ExcelRowData,
147
- ExcelCellData,
148
- ExcelXmlDrawingData,
149
- ExcelXmlSharedStringData,
150
- ExcelXmlSharedStringDataSi,
151
- ExcelXmlSharedStringDataText,
152
- ExcelXmlStyleData,
153
- ExcelXmlStyleDataXf,
154
- ExcelXmlStyleDataFill,
155
- ExcelXmlStyleDataBorder,
156
- ExcelXml,
157
- } from "@simplysm/excel";
158
- ```
159
-
160
- | Interface / Type | Description |
161
- |-----------------|-------------|
162
- | `ExcelXmlContentTypeData` | `[Content_Types].xml` document structure |
163
- | `ExcelXmlRelationshipData` | `.rels` relationship file structure |
164
- | `ExcelRelationshipData` | A single relationship entry |
165
- | `ExcelXmlWorkbookData` | `xl/workbook.xml` document structure |
166
- | `ExcelXmlWorksheetData` | `xl/worksheets/sheetN.xml` document structure |
167
- | `ExcelRowData` | A row element within worksheet XML |
168
- | `ExcelCellData` | A cell element within worksheet XML |
169
- | `ExcelXmlDrawingData` | Drawing XML structure (`xl/drawings/drawingN.xml`) |
170
- | `ExcelXmlSharedStringData` | Shared strings XML structure |
171
- | `ExcelXmlSharedStringDataSi` | A shared string entry (plain or rich text) |
172
- | `ExcelXmlSharedStringDataText` | Text content within a shared string entry |
173
- | `ExcelXmlStyleData` | Styles XML document structure |
174
- | `ExcelXmlStyleDataXf` | A cell format (`xf`) entry |
175
- | `ExcelXmlStyleDataFill` | A fill entry |
176
- | `ExcelXmlStyleDataBorder` | A border entry |
177
- | `ExcelXml` | Interface implemented by all XML handler classes |
178
-
179
- ### `ExcelUtils`
180
-
181
- A static utility class providing cell address conversion, date/number conversion, and number format processing.
182
-
183
- ```typescript
184
- import { ExcelUtils } from "@simplysm/excel";
185
-
186
- // Convert 0-based coordinates to "A1" notation
187
- ExcelUtils.stringifyAddr({ r: 0, c: 0 }); // "A1"
188
-
189
- // Convert column index to column letter(s)
190
- ExcelUtils.stringifyColAddr(0); // "A"
191
- ExcelUtils.stringifyColAddr(26); // "AA"
192
-
193
- // Convert row index to row number string
194
- ExcelUtils.stringifyRowAddr(0); // "1"
195
-
196
- // Parse cell address
197
- ExcelUtils.parseCellAddr("B3"); // { r: 2, c: 1 }
198
- ExcelUtils.parseRowAddr("B3"); // 2
199
- ExcelUtils.parseColAddr("B3"); // 1
200
-
201
- // Parse range address
202
- ExcelUtils.parseRangeAddr("A1:C3"); // { s: { r: 0, c: 0 }, e: { r: 2, c: 2 } }
203
-
204
- // Convert range coordinates to address string
205
- ExcelUtils.stringifyRangeAddr({ s: { r: 0, c: 0 }, e: { r: 2, c: 2 } }); // "A1:C3"
206
-
207
- // Date/number conversion (Excel serial date <-> JS timestamp)
208
- const excelNum = ExcelUtils.convertTimeTickToNumber(Date.now());
209
- const tick = ExcelUtils.convertNumberToTimeTick(excelNum);
210
-
211
- // Number format conversions
212
- ExcelUtils.convertNumFmtCodeToName("General"); // "number"
213
- ExcelUtils.convertNumFmtIdToName(14); // "DateOnly"
214
- ExcelUtils.convertNumFmtNameToId("DateTime"); // 22
215
- ```
216
-
217
- **Static Methods**
218
-
219
- | Method | Signature | Description |
220
- |--------|-----------|-------------|
221
- | `stringifyAddr` | `(point: ExcelAddressPoint) => string` | Convert coordinates to "A1" format |
222
- | `stringifyRowAddr` | `(r: number) => string` | Convert 0-based row index to row number string |
223
- | `stringifyColAddr` | `(c: number) => string` | Convert 0-based column index to column letter(s) |
224
- | `parseRowAddr` | `(addr: string) => number` | Extract 0-based row index from cell address |
225
- | `parseColAddr` | `(addr: string) => number` | Extract 0-based column index from cell address |
226
- | `parseCellAddr` | `(addr: string) => ExcelAddressPoint` | Convert cell address string to coordinates |
227
- | `parseRangeAddr` | `(rangeAddr: string) => ExcelAddressRangePoint` | Convert range address to coordinate pair |
228
- | `stringifyRangeAddr` | `(point: ExcelAddressRangePoint) => string` | Convert coordinate pair to range address string |
229
- | `convertTimeTickToNumber` | `(tick: number) => number` | Convert JS timestamp (ms) to Excel serial date number |
230
- | `convertNumberToTimeTick` | `(value: number) => number` | Convert Excel serial date number to JS timestamp (ms) |
231
- | `convertNumFmtCodeToName` | `(numFmtCode: string) => ExcelNumberFormat` | Convert format code string to format name |
232
- | `convertNumFmtIdToName` | `(numFmtId: number) => ExcelNumberFormat` | Convert built-in format ID to format name |
233
- | `convertNumFmtNameToId` | `(numFmtName: ExcelNumberFormat) => number` | Convert format name to built-in format ID |
234
-
235
- ---
236
-
237
- ## Core Classes
238
-
239
- ### `ExcelWorkbook`
240
-
241
- The top-level class for reading and writing Excel workbooks. Internally manages ZIP resources; resources must be released after use.
242
-
243
- Supports `await using` (ES2022 `Symbol.asyncDispose`). Internally uses lazy-loading: XML inside the ZIP is parsed only at the point of access, keeping memory usage low even with large files.
244
-
245
- ```typescript
246
- import { ExcelWorkbook } from "@simplysm/excel";
247
-
248
- // Open an existing workbook
249
- const bytes: Uint8Array = /* file bytes */;
250
- await using wb = new ExcelWorkbook(bytes);
251
-
252
- // Create a new workbook
253
- await using wb2 = new ExcelWorkbook();
254
- const ws = await wb2.addWorksheet("Sheet1");
255
-
256
- // Get all worksheet names
257
- const names = await wb.getWorksheetNames();
258
-
259
- // Access a worksheet by index or name
260
- const ws0 = await wb.getWorksheet(0);
261
- const ws1 = await wb.getWorksheet("Sheet1");
262
-
263
- // Export
264
- const exportedBytes = await wb.toBytes();
265
- const blob = await wb.toBlob();
266
-
267
- // Manual resource management
268
- const wb3 = new ExcelWorkbook(bytes);
269
- try {
270
- const ws = await wb3.getWorksheet(0);
271
- // ...
272
- } finally {
273
- await wb3.close();
274
- }
275
- ```
276
-
277
- **Constructor**
278
-
279
- ```typescript
280
- constructor(arg?: Blob | Bytes)
281
- ```
282
-
283
- - `arg` — Existing Excel file data (`Blob` or `Uint8Array`). Creates a new empty workbook if omitted.
284
-
285
- **Properties**
286
-
287
- | Property | Type | Description |
288
- |----------|------|-------------|
289
- | `zipCache` | `ZipCache` | Internal ZIP cache (advanced use) |
290
-
291
- **Methods**
292
-
293
- | Method | Signature | Description |
294
- |--------|-----------|-------------|
295
- | `getWorksheetNames` | `() => Promise<string[]>` | Return all worksheet names in the workbook |
296
- | `addWorksheet` | `(name: string) => Promise<ExcelWorksheet>` | Create and return a new worksheet |
297
- | `getWorksheet` | `(nameOrIndex: string \| number) => Promise<ExcelWorksheet>` | Look up a worksheet by name or 0-based index |
298
- | `toBytes` | `() => Promise<Bytes>` | Export workbook as a `Uint8Array` byte array |
299
- | `toBlob` | `() => Promise<Blob>` | Export workbook as a `Blob` |
300
- | `close` | `() => Promise<void>` | Release all resources (idempotent) |
301
- | `[Symbol.asyncDispose]` | `() => Promise<void>` | Called automatically by `await using` |
302
-
303
- ---
304
-
305
- ### `ExcelWorksheet`
306
-
307
- Represents a single worksheet. Provides cell access, row/column copy operations, data import/export, view settings, and image insertion.
308
-
309
- ```typescript
310
- import { ExcelWorksheet } from "@simplysm/excel";
311
-
312
- // Obtained from ExcelWorkbook
313
- const ws = await wb.getWorksheet(0);
314
-
315
- // Name
316
- const name = await ws.getName();
317
- await ws.setName("NewName");
318
-
319
- // Cell access
320
- const cell = ws.cell(0, 0); // row 0, col 0 -> A1
321
- const row = ws.row(1); // row 1 (second row)
322
- const col = ws.col(2); // col 2 -> column C
323
-
324
- // Range and bulk cell access
325
- const range = await ws.getRange();
326
- const cells = await ws.getCells(); // ExcelCell[][]
327
-
328
- // Copy operations
329
- await ws.copyRow(0, 5); // copy row 0 to row 5
330
- await ws.copyRowStyle(0, 5); // copy style of row 0 to row 5
331
- await ws.copyCell({ r: 0, c: 0 }, { r: 5, c: 0 }); // copy single cell
332
- await ws.copyCellStyle({ r: 0, c: 0 }, { r: 5, c: 0 });
333
- await ws.insertCopyRow(0, 3); // insert-copy row 0 at position 3, shifting rows down
334
-
335
- // Read as table (first row = headers)
336
- const table = await ws.getDataTable();
337
- const table2 = await ws.getDataTable({
338
- headerRowIndex: 0,
339
- checkEndColIndex: 0,
340
- usableHeaderNameFn: (name) => name !== "ignore",
341
- });
342
-
343
- // Write data
344
- await ws.setDataMatrix([[1, "hello"], [2, "world"]]);
345
- await ws.setRecords([{ Name: "Alice", Age: 30 }]);
346
-
347
- // View settings
348
- await ws.setZoom(85); // 85%
349
- await ws.freezeAt({ r: 1 }); // freeze first row
350
- await ws.freezeAt({ c: 1 }); // freeze first column
351
- await ws.freezeAt({ r: 1, c: 1 }); // freeze both
352
-
353
- // Insert image
354
- await ws.addImage({
355
- bytes: imageBytes,
356
- ext: "png",
357
- from: { r: 0, c: 0 },
358
- to: { r: 5, c: 3 },
359
- });
360
- ```
361
-
362
- **Methods**
363
-
364
- | Method | Signature | Description |
365
- |--------|-----------|-------------|
366
- | `getName` | `() => Promise<string>` | Return the worksheet name |
367
- | `setName` | `(newName: string) => Promise<void>` | Rename the worksheet |
368
- | `row` | `(r: number) => ExcelRow` | Return the `ExcelRow` at 0-based row index |
369
- | `cell` | `(r: number, c: number) => ExcelCell` | Return the `ExcelCell` at 0-based row/column |
370
- | `col` | `(c: number) => ExcelCol` | Return the `ExcelCol` at 0-based column index |
371
- | `getRange` | `() => Promise<ExcelAddressRangePoint>` | Return the used data range |
372
- | `getCells` | `() => Promise<ExcelCell[][]>` | Return all cells as a 2D array (row-major) |
373
- | `copyRow` | `(srcR: number, targetR: number) => Promise<void>` | Copy source row to target row (overwrite) |
374
- | `copyRowStyle` | `(srcR: number, targetR: number) => Promise<void>` | Copy style from source row to target row |
375
- | `copyCell` | `(srcAddr: ExcelAddressPoint, targetAddr: ExcelAddressPoint) => Promise<void>` | Copy a single cell |
376
- | `copyCellStyle` | `(srcAddr: ExcelAddressPoint, targetAddr: ExcelAddressPoint) => Promise<void>` | Copy style from source cell to target cell |
377
- | `insertCopyRow` | `(srcR: number, targetR: number) => Promise<void>` | Insert-copy source row at target position (shifts rows down) |
378
- | `getDataTable` | `(opt?) => Promise<Record<string, ExcelValueType>[]>` | Read worksheet as a header-keyed record array |
379
- | `setDataMatrix` | `(matrix: ExcelValueType[][]) => Promise<void>` | Write a 2D array to the worksheet |
380
- | `setRecords` | `(records: Record<string, ExcelValueType>[]) => Promise<void>` | Write records with auto-generated header row |
381
- | `setZoom` | `(percent: number) => Promise<void>` | Set the worksheet zoom level |
382
- | `freezeAt` | `(point: { r?: number; c?: number }) => Promise<void>` | Set freeze panes |
383
- | `addImage` | `(opts) => Promise<void>` | Insert an image into the worksheet |
384
-
385
- **`getDataTable` options**
386
-
387
- ```typescript
388
- {
389
- headerRowIndex?: number; // Row index of the header row (default: first row in range)
390
- checkEndColIndex?: number; // Column whose empty value signals end of data
391
- usableHeaderNameFn?: (headerName: string) => boolean; // Filter which headers to include
392
- }
393
- ```
394
-
395
- **`addImage` options**
396
-
397
- ```typescript
398
- {
399
- bytes: Bytes; // Image binary data (Uint8Array)
400
- ext: string; // File extension, e.g. "png", "jpg"
401
- from: { r: number; c: number; rOff?: number | string; cOff?: number | string }; // Start cell (0-based), optional EMU offset
402
- to?: { r: number; c: number; rOff?: number | string; cOff?: number | string }; // End cell (optional; defaults to from.r+1, from.c+1)
403
- }
404
- ```
405
-
406
- ---
407
-
408
- ### `ExcelRow`
409
-
410
- Represents a row in a worksheet. Provides access to individual cells and all cells in the row.
411
-
412
- ```typescript
413
- import { ExcelRow } from "@simplysm/excel";
414
-
415
- // Obtained from ExcelWorksheet
416
- const row = ws.row(0);
417
-
418
- // Access a cell by column index (0-based)
419
- const cell = row.cell(2); // column C
420
-
421
- // Get all cells in the row (within used range)
422
- const cells = await row.getCells();
423
- ```
424
-
425
- **Methods**
426
-
427
- | Method | Signature | Description |
428
- |--------|-----------|-------------|
429
- | `cell` | `(c: number) => ExcelCell` | Return the `ExcelCell` at the given 0-based column index |
430
- | `getCells` | `() => Promise<ExcelCell[]>` | Return all cells in the row within the worksheet's used range |
431
-
432
- ---
433
-
434
- ### `ExcelCol`
435
-
436
- Represents a column in a worksheet. Provides access to individual cells, all cells in the column, and column width configuration.
437
-
438
- ```typescript
439
- import { ExcelCol } from "@simplysm/excel";
440
-
441
- // Obtained from ExcelWorksheet
442
- const col = ws.col(0); // column A
443
-
444
- // Access a cell by row index (0-based)
445
- const cell = col.cell(3); // row 3
446
-
447
- // Get all cells in the column (within used range)
448
- const cells = await col.getCells();
449
-
450
- // Set column width
451
- await col.setWidth(20);
452
- ```
453
-
454
- **Methods**
455
-
456
- | Method | Signature | Description |
457
- |--------|-----------|-------------|
458
- | `cell` | `(r: number) => ExcelCell` | Return the `ExcelCell` at the given 0-based row index |
459
- | `getCells` | `() => Promise<ExcelCell[]>` | Return all cells in the column within the worksheet's used range |
460
- | `setWidth` | `(size: number) => Promise<void>` | Set the column width |
461
-
462
- ---
463
-
464
- ### `ExcelCell`
465
-
466
- Represents a single cell. Provides value read/write, formula access, style configuration, and cell merge.
467
-
468
- All methods are `async` because XML sub-files (SharedStrings, Styles) are loaded lazily on demand.
469
-
470
- ```typescript
471
- import { ExcelCell } from "@simplysm/excel";
472
-
473
- // Obtained from ExcelWorksheet, ExcelRow, or ExcelCol
474
- const cell = ws.cell(0, 0); // A1
475
-
476
- // Cell address (0-based)
477
- console.log(cell.addr); // { r: 0, c: 0 }
478
-
479
- // Read/write values
480
- await cell.setValue("Hello");
481
- await cell.setValue(42);
482
- await cell.setValue(true);
483
- await cell.setValue(new DateOnly(Date.now()));
484
- await cell.setValue(new DateTime(Date.now()));
485
- await cell.setValue(new Time(Date.now()));
486
- await cell.setValue(undefined); // deletes the cell
487
-
488
- const value = await cell.getValue(); // ExcelValueType
489
-
490
- // Formulas
491
- await cell.setFormula("=SUM(A1:A10)");
492
- await cell.setFormula(undefined); // removes formula
493
- const formula = await cell.getFormula();
494
-
495
- // Style
496
- await cell.setStyle({
497
- background: "00FFFF00", // ARGB 8-digit hex (yellow)
498
- border: ["left", "right", "top", "bottom"],
499
- horizontalAlign: "center",
500
- verticalAlign: "center",
501
- numberFormat: "number",
502
- });
503
-
504
- // Raw style ID (advanced use)
505
- const styleId = await cell.getStyleId();
506
- await cell.setStyleId("3");
507
-
508
- // Merge cells: merge from this cell (A1) to C3
509
- await cell.merge(2, 2); // end row=2, end col=2
510
- ```
511
-
512
- **Properties**
513
-
514
- | Property | Type | Description |
515
- |----------|------|-------------|
516
- | `addr` | `ExcelAddressPoint` | Cell address (0-based `{ r, c }`) |
517
-
518
- **Methods**
519
-
520
- | Method | Signature | Description |
521
- |--------|-----------|-------------|
522
- | `getValue` | `() => Promise<ExcelValueType>` | Read the cell value |
523
- | `setValue` | `(val: ExcelValueType) => Promise<void>` | Write the cell value (`undefined` deletes the cell) |
524
- | `getFormula` | `() => Promise<string \| undefined>` | Read the cell formula |
525
- | `setFormula` | `(val: string \| undefined) => Promise<void>` | Write the cell formula (`undefined` removes it) |
526
- | `getStyleId` | `() => Promise<string \| undefined>` | Read the raw style ID |
527
- | `setStyleId` | `(styleId: string \| undefined) => Promise<void>` | Set the raw style ID |
528
- | `setStyle` | `(opts: ExcelStyleOptions) => Promise<void>` | Apply style options to the cell |
529
- | `merge` | `(r: number, c: number) => Promise<void>` | Merge from this cell to the given end coordinates (0-based) |
530
-
531
- ---
532
-
533
- ## Wrapper Classes
534
-
535
- ### `ExcelWrapper`
536
-
537
- A Zod schema-based high-level wrapper that provides type-safe reading and writing of Excel files. Use `.describe()` on schema fields to specify the Excel column header name.
538
-
539
- ```typescript
540
- import { ExcelWrapper } from "@simplysm/excel";
541
- import { z } from "zod";
542
-
543
- const schema = z.object({
544
- name: z.string().describe("Name"),
545
- age: z.number().describe("Age"),
546
- joinDate: z.instanceof(DateOnly).optional().describe("Join Date"),
547
- });
548
-
549
- const wrapper = new ExcelWrapper(schema);
550
-
551
- // Read Excel file into typed records
552
- const records = await wrapper.read(fileBytes);
553
- const records2 = await wrapper.read(fileBytes, "Sheet1");
554
- const records3 = await wrapper.read(fileBytes, 0, { excludes: ["age"] });
555
-
556
- // Write records to Excel workbook
557
- await using wb = await wrapper.write("Members", records);
558
- const bytes = await wb.toBytes();
559
-
560
- // Write with excludes
561
- await using wb2 = await wrapper.write("Members", records, { excludes: ["joinDate"] });
562
- ```
563
-
564
- **Constructor**
565
-
566
- ```typescript
567
- constructor(schema: TSchema extends z.ZodObject<z.ZodRawShape>)
568
- ```
569
-
570
- **Methods**
571
-
572
- | Method | Signature | Description |
573
- |--------|-----------|-------------|
574
- | `read` | `(file: Bytes \| Blob, wsNameOrIndex?: string \| number, options?: { excludes?: (keyof TSchema)[] }) => Promise<z.infer<TSchema>[]>` | Read an Excel file into a typed record array |
575
- | `write` | `(wsName: string, records: Partial<z.infer<TSchema>>[], options?: { excludes?: (keyof TSchema)[] }) => Promise<ExcelWorkbook>` | Write records to a new `ExcelWorkbook` (caller manages lifecycle) |
576
-
577
- **Behavior Notes**
578
-
579
- - Header names are taken from Zod field `.describe()` values; if not set, the field key is used.
580
- - `read` throws if no data rows are found after the header row.
581
- - `read` validates each row with the Zod schema and throws on validation failure.
582
- - `write` automatically applies borders to all data cells, highlights required (non-optional, non-boolean) header cells with a yellow background (`"00FFFF00"`), sets zoom to 85%, and freezes the first row.
583
- - The `ExcelWorkbook` returned by `write` must be closed by the caller (`await using` or `.close()`).