@simplysm/excel 13.0.81 → 13.0.83

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/README.md +371 -0
  2. package/package.json +3 -4
package/README.md ADDED
@@ -0,0 +1,371 @@
1
+ # @simplysm/excel
2
+
3
+ Excel file (.xlsx) processing library for reading, writing, and manipulating workbooks. Supports both low-level cell operations and high-level schema-based data mapping via Zod.
4
+
5
+ Works in both Node.js and browser environments. Uses lazy-loading architecture for memory-efficient handling of large files.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @simplysm/excel
11
+ ```
12
+
13
+ **Peer dependency:** `@simplysm/core-common`
14
+
15
+ ## Quick Start
16
+
17
+ ### Create and export a workbook
18
+
19
+ ```typescript
20
+ import { ExcelWorkbook } from "@simplysm/excel";
21
+
22
+ await using wb = new ExcelWorkbook();
23
+ const ws = await wb.addWorksheet("Sheet1");
24
+
25
+ await ws.cell(0, 0).setValue("Name");
26
+ await ws.cell(0, 1).setValue("Age");
27
+ await ws.cell(1, 0).setValue("Alice");
28
+ await ws.cell(1, 1).setValue(30);
29
+
30
+ const bytes = await wb.toBytes(); // Uint8Array
31
+ const blob = await wb.toBlob(); // Blob (for browser downloads)
32
+ ```
33
+
34
+ ### Read an existing workbook
35
+
36
+ ```typescript
37
+ import { ExcelWorkbook } from "@simplysm/excel";
38
+
39
+ await using wb = new ExcelWorkbook(fileBytes); // Uint8Array or Blob
40
+ const ws = await wb.getWorksheet(0); // by index
41
+ // const ws = await wb.getWorksheet("Sheet1"); // or by name
42
+
43
+ const value = await ws.cell(0, 0).getValue(); // read cell value
44
+ ```
45
+
46
+ ### Schema-based read/write with ExcelWrapper
47
+
48
+ ```typescript
49
+ import { z } from "zod";
50
+ import { ExcelWrapper } from "@simplysm/excel";
51
+
52
+ const schema = z.object({
53
+ name: z.string().describe("Name"), // .describe() sets the Excel header
54
+ age: z.number().describe("Age"),
55
+ email: z.string().optional().describe("Email"),
56
+ active: z.boolean().default(false).describe("Active"),
57
+ });
58
+
59
+ const wrapper = new ExcelWrapper(schema);
60
+
61
+ // Write records to Excel
62
+ await using wb = await wrapper.write("Users", [
63
+ { name: "Alice", age: 30, email: "alice@example.com", active: true },
64
+ { name: "Bob", age: 25 },
65
+ ]);
66
+ const bytes = await wb.toBytes();
67
+
68
+ // Read records from Excel
69
+ const records = await wrapper.read(bytes, "Users");
70
+ // records[0] => { name: "Alice", age: 30, email: "alice@example.com", active: true }
71
+ ```
72
+
73
+ ## API Reference
74
+
75
+ ### ExcelWorkbook
76
+
77
+ Excel workbook processing class. Manages ZIP resources internally and uses lazy-loading for memory efficiency.
78
+
79
+ **Resource management:** Always release resources after use via `await using` (recommended) or `close()`.
80
+
81
+ ```typescript
82
+ // Recommended: automatic cleanup
83
+ await using wb = new ExcelWorkbook(bytes);
84
+
85
+ // Alternative: manual cleanup
86
+ const wb = new ExcelWorkbook(bytes);
87
+ try {
88
+ // ... operations
89
+ } finally {
90
+ await wb.close();
91
+ }
92
+ ```
93
+
94
+ #### Constructor
95
+
96
+ ```typescript
97
+ new ExcelWorkbook() // create empty workbook
98
+ new ExcelWorkbook(bytes: Bytes) // open from Uint8Array
99
+ new ExcelWorkbook(blob: Blob) // open from Blob
100
+ ```
101
+
102
+ #### Methods
103
+
104
+ | Method | Returns | Description |
105
+ |--------|---------|-------------|
106
+ | `getWorksheetNames()` | `Promise<string[]>` | Return all worksheet names |
107
+ | `getWorksheet(index: number)` | `Promise<ExcelWorksheet>` | Get worksheet by 0-based index |
108
+ | `getWorksheet(name: string)` | `Promise<ExcelWorksheet>` | Get worksheet by name |
109
+ | `addWorksheet(name: string)` | `Promise<ExcelWorksheet>` | Create a new worksheet |
110
+ | `toBytes()` | `Promise<Bytes>` | Export workbook as byte array |
111
+ | `toBlob()` | `Promise<Blob>` | Export workbook as Blob |
112
+ | `close()` | `Promise<void>` | Release resources (safe to call multiple times) |
113
+
114
+ ---
115
+
116
+ ### ExcelWorksheet
117
+
118
+ Represents a worksheet. Provides cell access, row/column operations, data table processing, and image insertion.
119
+
120
+ #### Cell Access
121
+
122
+ | Method | Returns | Description |
123
+ |--------|---------|-------------|
124
+ | `cell(r, c)` | `ExcelCell` | Get cell at row `r`, column `c` (0-based) |
125
+ | `row(r)` | `ExcelRow` | Get row object (0-based) |
126
+ | `col(c)` | `ExcelCol` | Get column object (0-based) |
127
+ | `getCells()` | `Promise<ExcelCell[][]>` | Get all cells as a 2D array |
128
+ | `getRange()` | `Promise<ExcelAddressRangePoint>` | Get the data range of the worksheet |
129
+
130
+ #### Name
131
+
132
+ | Method | Returns | Description |
133
+ |--------|---------|-------------|
134
+ | `getName()` | `Promise<string>` | Get worksheet name |
135
+ | `setName(name)` | `Promise<void>` | Rename worksheet |
136
+
137
+ #### Data Operations
138
+
139
+ | Method | Returns | Description |
140
+ |--------|---------|-------------|
141
+ | `getDataTable(opt?)` | `Promise<Record<string, ExcelValueType>[]>` | Read data as record array (first row = headers) |
142
+ | `setDataMatrix(matrix)` | `Promise<void>` | Write 2D array data |
143
+ | `setRecords(records)` | `Promise<void>` | Write record array (auto-generates headers) |
144
+
145
+ **`getDataTable` options:**
146
+
147
+ | Option | Type | Description |
148
+ |--------|------|-------------|
149
+ | `headerRowIndex` | `number` | Header row index (default: first row of range) |
150
+ | `checkEndColIndex` | `number` | Column index to detect data end (stops when empty) |
151
+ | `usableHeaderNameFn` | `(name: string) => boolean` | Filter function for usable headers |
152
+
153
+ #### Copy Operations
154
+
155
+ | Method | Returns | Description |
156
+ |--------|---------|-------------|
157
+ | `copyRow(srcR, targetR)` | `Promise<void>` | Copy row (overwrite target) |
158
+ | `copyCell(srcAddr, targetAddr)` | `Promise<void>` | Copy cell |
159
+ | `copyRowStyle(srcR, targetR)` | `Promise<void>` | Copy row style only |
160
+ | `copyCellStyle(srcAddr, targetAddr)` | `Promise<void>` | Copy cell style only |
161
+ | `insertCopyRow(srcR, targetR)` | `Promise<void>` | Insert-copy row (shifts existing rows down) |
162
+
163
+ #### View Settings
164
+
165
+ | Method | Returns | Description |
166
+ |--------|---------|-------------|
167
+ | `setZoom(percent)` | `Promise<void>` | Set zoom scale |
168
+ | `freezeAt({ r?, c? })` | `Promise<void>` | Freeze panes at row/column |
169
+
170
+ #### Image
171
+
172
+ ```typescript
173
+ await ws.addImage({
174
+ bytes: imageBytes, // image binary data (Uint8Array)
175
+ ext: "png", // file extension
176
+ from: { r: 0, c: 0 }, // start position (0-based)
177
+ to: { r: 5, c: 3 }, // end position (optional)
178
+ });
179
+ ```
180
+
181
+ | Parameter | Type | Description |
182
+ |-----------|------|-------------|
183
+ | `bytes` | `Bytes` | Image binary data |
184
+ | `ext` | `string` | Image extension (png, jpg, etc.) |
185
+ | `from` | `{ r, c, rOff?, cOff? }` | Start position. `rOff`/`cOff` are EMU offsets. |
186
+ | `to` | `{ r, c, rOff?, cOff? }` | End position. Defaults to one cell from `from`. |
187
+
188
+ ---
189
+
190
+ ### ExcelCell
191
+
192
+ Represents a single cell. All methods are async for lazy-loading efficiency.
193
+
194
+ #### Properties
195
+
196
+ | Property | Type | Description |
197
+ |----------|------|-------------|
198
+ | `addr` | `ExcelAddressPoint` | Cell address (`{ r, c }`, 0-based) |
199
+
200
+ #### Value
201
+
202
+ | Method | Returns | Description |
203
+ |--------|---------|-------------|
204
+ | `getValue()` | `Promise<ExcelValueType>` | Get cell value |
205
+ | `setValue(val)` | `Promise<void>` | Set cell value (`undefined` deletes the cell) |
206
+ | `getFormula()` | `Promise<string \| undefined>` | Get cell formula |
207
+ | `setFormula(val)` | `Promise<void>` | Set cell formula (`undefined` removes it) |
208
+
209
+ Supported value types (`ExcelValueType`): `string`, `number`, `boolean`, `DateOnly`, `DateTime`, `Time`, `undefined`
210
+
211
+ #### Style
212
+
213
+ | Method | Returns | Description |
214
+ |--------|---------|-------------|
215
+ | `setStyle(opts)` | `Promise<void>` | Set cell style |
216
+ | `getStyleId()` | `Promise<string \| undefined>` | Get raw style ID |
217
+ | `setStyleId(id)` | `Promise<void>` | Set raw style ID |
218
+
219
+ **Style options (`ExcelStyleOptions`):**
220
+
221
+ ```typescript
222
+ await cell.setStyle({
223
+ background: "00FF0000", // ARGB hex (8 digits)
224
+ border: ["left", "right", "top", "bottom"], // border positions
225
+ horizontalAlign: "center", // "left" | "center" | "right"
226
+ verticalAlign: "center", // "top" | "center" | "bottom"
227
+ numberFormat: "number", // "number" | "string" | "DateOnly" | "DateTime" | "Time"
228
+ });
229
+ ```
230
+
231
+ #### Merge
232
+
233
+ | Method | Returns | Description |
234
+ |--------|---------|-------------|
235
+ | `merge(r, c)` | `Promise<void>` | Merge from this cell to end position `(r, c)` |
236
+
237
+ ```typescript
238
+ // Merge A1:C3 (3 rows x 3 columns)
239
+ await ws.cell(0, 0).merge(2, 2);
240
+ ```
241
+
242
+ ---
243
+
244
+ ### ExcelRow
245
+
246
+ Represents a worksheet row.
247
+
248
+ | Method | Returns | Description |
249
+ |--------|---------|-------------|
250
+ | `cell(c)` | `ExcelCell` | Get cell at column `c` (0-based) |
251
+ | `getCells()` | `Promise<ExcelCell[]>` | Get all cells in the row |
252
+
253
+ ---
254
+
255
+ ### ExcelCol
256
+
257
+ Represents a worksheet column.
258
+
259
+ | Method | Returns | Description |
260
+ |--------|---------|-------------|
261
+ | `cell(r)` | `ExcelCell` | Get cell at row `r` (0-based) |
262
+ | `getCells()` | `Promise<ExcelCell[]>` | Get all cells in the column |
263
+ | `setWidth(size)` | `Promise<void>` | Set column width |
264
+
265
+ ---
266
+
267
+ ### ExcelWrapper\<TSchema\>
268
+
269
+ Zod schema-based Excel wrapper for type-safe read/write. Define a Zod object schema where each field's `.describe()` sets the Excel column header name.
270
+
271
+ #### Constructor
272
+
273
+ ```typescript
274
+ new ExcelWrapper(schema: z.ZodObject<z.ZodRawShape>)
275
+ ```
276
+
277
+ #### Methods
278
+
279
+ | Method | Returns | Description |
280
+ |--------|---------|-------------|
281
+ | `read(file, wsNameOrIndex?, options?)` | `Promise<z.infer<TSchema>[]>` | Read Excel file into typed record array |
282
+ | `write(wsName, records, options?)` | `Promise<ExcelWorkbook>` | Write records to a new workbook |
283
+
284
+ **`read` parameters:**
285
+
286
+ | Parameter | Type | Default | Description |
287
+ |-----------|------|---------|-------------|
288
+ | `file` | `Bytes \| Blob` | | Excel file data |
289
+ | `wsNameOrIndex` | `string \| number` | `0` | Worksheet name or index |
290
+ | `options.excludes` | `(keyof T)[]` | | Fields to exclude from reading |
291
+
292
+ **`write` parameters:**
293
+
294
+ | Parameter | Type | Description |
295
+ |-----------|------|-------------|
296
+ | `wsName` | `string` | Worksheet name |
297
+ | `records` | `Partial<T>[]` | Record array to write |
298
+ | `options.excludes` | `(keyof T)[]` | Fields to exclude from columns |
299
+
300
+ **Write behavior:**
301
+ - Generates headers from schema field descriptions
302
+ - Applies border style to all data cells
303
+ - Highlights required field headers with yellow background
304
+ - Sets zoom to 85% and freezes the header row
305
+
306
+ **Supported Zod types:** `z.string()`, `z.number()`, `z.boolean()`, `z.instanceof(DateOnly)`, `z.instanceof(DateTime)`, `z.instanceof(Time)`. Supports `z.optional()`, `z.nullable()`, `z.default()` wrappers.
307
+
308
+ ---
309
+
310
+ ### ExcelUtils
311
+
312
+ Static utility class for Excel address conversion and date/number processing.
313
+
314
+ #### Address Conversion
315
+
316
+ | Method | Returns | Description |
317
+ |--------|---------|-------------|
318
+ | `stringifyAddr({ r, c })` | `string` | Coordinates to "A1" format |
319
+ | `stringifyRowAddr(r)` | `string` | Row index to string (0 -> "1") |
320
+ | `stringifyColAddr(c)` | `string` | Column index to string (0 -> "A", 26 -> "AA") |
321
+ | `parseCellAddr(addr)` | `ExcelAddressPoint` | "B3" -> `{ r: 2, c: 1 }` |
322
+ | `parseRowAddr(addr)` | `number` | Extract row index from address |
323
+ | `parseColAddr(addr)` | `number` | Extract column index from address |
324
+ | `parseRangeAddr(rangeAddr)` | `ExcelAddressRangePoint` | "A1:C3" -> `{ s: {r:0,c:0}, e: {r:2,c:2} }` |
325
+ | `stringifyRangeAddr(point)` | `string` | Range coordinates to "A1:C3" format |
326
+
327
+ #### Date/Number Conversion
328
+
329
+ | Method | Returns | Description |
330
+ |--------|---------|-------------|
331
+ | `convertTimeTickToNumber(tick)` | `number` | JS timestamp (ms) to Excel date number |
332
+ | `convertNumberToTimeTick(value)` | `number` | Excel date number to JS timestamp (ms) |
333
+
334
+ #### Number Format
335
+
336
+ | Method | Returns | Description |
337
+ |--------|---------|-------------|
338
+ | `convertNumFmtIdToName(id)` | `ExcelNumberFormat` | Built-in format ID to name |
339
+ | `convertNumFmtCodeToName(code)` | `ExcelNumberFormat` | Format code string to name |
340
+ | `convertNumFmtNameToId(name)` | `number` | Format name to built-in ID |
341
+
342
+ ---
343
+
344
+ ### Types
345
+
346
+ ```typescript
347
+ /** Supported cell value types */
348
+ type ExcelValueType = number | string | DateOnly | DateTime | Time | boolean | undefined;
349
+
350
+ /** Number format names */
351
+ type ExcelNumberFormat = "number" | "string" | "DateOnly" | "DateTime" | "Time";
352
+
353
+ /** Cell address (0-based) */
354
+ interface ExcelAddressPoint { r: number; c: number; }
355
+
356
+ /** Range address (0-based) */
357
+ interface ExcelAddressRangePoint { s: ExcelAddressPoint; e: ExcelAddressPoint; }
358
+
359
+ /** Cell style options */
360
+ interface ExcelStyleOptions {
361
+ background?: string; // ARGB hex (e.g. "00FF0000")
362
+ border?: ExcelBorderPosition[]; // "left" | "right" | "top" | "bottom"
363
+ horizontalAlign?: ExcelHorizontalAlign; // "left" | "center" | "right"
364
+ verticalAlign?: ExcelVerticalAlign; // "top" | "center" | "bottom"
365
+ numberFormat?: ExcelNumberFormat;
366
+ }
367
+
368
+ type ExcelBorderPosition = "left" | "right" | "top" | "bottom";
369
+ type ExcelHorizontalAlign = "center" | "left" | "right";
370
+ type ExcelVerticalAlign = "center" | "top" | "bottom";
371
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/excel",
3
- "version": "13.0.81",
3
+ "version": "13.0.83",
4
4
  "description": "Excel file processing library",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -15,13 +15,12 @@
15
15
  "files": [
16
16
  "dist",
17
17
  "src",
18
- "tests",
19
- "docs"
18
+ "tests"
20
19
  ],
21
20
  "sideEffects": false,
22
21
  "dependencies": {
23
22
  "mime": "^4.1.0",
24
23
  "zod": "^4.3.6",
25
- "@simplysm/core-common": "13.0.81"
24
+ "@simplysm/core-common": "13.0.83"
26
25
  }
27
26
  }