@niicojs/excel 0.2.4 → 0.2.6
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/LICENSE +20 -20
- package/README.md +8 -232
- package/dist/index.cjs +222 -430
- package/dist/index.d.cts +17 -117
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +17 -117
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +223 -427
- package/package.json +1 -1
- package/src/index.ts +1 -15
- package/src/pivot-cache.ts +30 -17
- package/src/pivot-table.ts +52 -137
- package/src/range.ts +2 -15
- package/src/styles.ts +65 -64
- package/src/types.ts +0 -23
- package/src/utils/address.ts +1 -4
- package/src/utils/xml.ts +7 -0
- package/src/workbook.ts +4 -18
- package/src/worksheet.ts +7 -235
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 niico
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 niico
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -9,9 +9,6 @@ A TypeScript library for Excel/OpenXML manipulation with maximum format preserva
|
|
|
9
9
|
- Full formula support (read/write/preserve)
|
|
10
10
|
- Cell styles (fonts, fills, borders, alignment)
|
|
11
11
|
- Merged cells
|
|
12
|
-
- Column widths and row heights
|
|
13
|
-
- Freeze panes
|
|
14
|
-
- Pivot tables with fluent API
|
|
15
12
|
- Sheet operations (add, delete, rename, copy)
|
|
16
13
|
- Create sheets from arrays of objects (`addSheetFromData`)
|
|
17
14
|
- Convert sheets to JSON arrays (`toJson`)
|
|
@@ -142,47 +139,6 @@ sheet.unmergeCells('A1:C1');
|
|
|
142
139
|
console.log(sheet.mergedCells); // ['A1:C3', 'D5:E10', ...]
|
|
143
140
|
```
|
|
144
141
|
|
|
145
|
-
## Column Widths and Row Heights
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
const sheet = wb.sheet(0);
|
|
149
|
-
|
|
150
|
-
// Set column width (by letter or 0-based index)
|
|
151
|
-
sheet.setColumnWidth('A', 20);
|
|
152
|
-
sheet.setColumnWidth(1, 15); // Column B
|
|
153
|
-
|
|
154
|
-
// Get column width
|
|
155
|
-
const width = sheet.getColumnWidth('A'); // 20 or undefined
|
|
156
|
-
|
|
157
|
-
// Set row height (0-based index)
|
|
158
|
-
sheet.setRowHeight(0, 30); // First row
|
|
159
|
-
|
|
160
|
-
// Get row height
|
|
161
|
-
const height = sheet.getRowHeight(0); // 30 or undefined
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## Freeze Panes
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
const sheet = wb.sheet(0);
|
|
168
|
-
|
|
169
|
-
// Freeze first row (header)
|
|
170
|
-
sheet.freezePane(1, 0);
|
|
171
|
-
|
|
172
|
-
// Freeze first column
|
|
173
|
-
sheet.freezePane(0, 1);
|
|
174
|
-
|
|
175
|
-
// Freeze first row and first column
|
|
176
|
-
sheet.freezePane(1, 1);
|
|
177
|
-
|
|
178
|
-
// Unfreeze
|
|
179
|
-
sheet.freezePane(0, 0);
|
|
180
|
-
|
|
181
|
-
// Get current freeze pane configuration
|
|
182
|
-
const frozen = sheet.getFrozenPane();
|
|
183
|
-
// { row: 1, col: 0 } or null
|
|
184
|
-
```
|
|
185
|
-
|
|
186
142
|
## Sheet Operations
|
|
187
143
|
|
|
188
144
|
```typescript
|
|
@@ -209,56 +165,6 @@ wb.copySheet('RawData', 'RawData_Backup');
|
|
|
209
165
|
wb.deleteSheet('Summary');
|
|
210
166
|
```
|
|
211
167
|
|
|
212
|
-
## Pivot Tables
|
|
213
|
-
|
|
214
|
-
Create pivot tables with a fluent API:
|
|
215
|
-
|
|
216
|
-
```typescript
|
|
217
|
-
const wb = await Workbook.fromFile('sales-data.xlsx');
|
|
218
|
-
|
|
219
|
-
// Create a pivot table from source data
|
|
220
|
-
const pivot = wb.createPivotTable({
|
|
221
|
-
name: 'SalesPivot',
|
|
222
|
-
source: 'Data!A1:E100', // Source range with headers
|
|
223
|
-
target: 'Summary!A3', // Where to place the pivot table
|
|
224
|
-
refreshOnLoad: true, // Refresh when file opens (default: true)
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// Configure fields using fluent API
|
|
228
|
-
pivot
|
|
229
|
-
.addRowField('Region') // Group by region
|
|
230
|
-
.addRowField('Product') // Then by product
|
|
231
|
-
.addColumnField('Year') // Columns by year
|
|
232
|
-
.addValueField('Sales', 'sum', 'Total Sales') // Sum of sales
|
|
233
|
-
.addValueField('Quantity', 'count', 'Order Count') // Count of orders
|
|
234
|
-
.addFilterField('Category'); // Page filter
|
|
235
|
-
|
|
236
|
-
// Sort and filter fields
|
|
237
|
-
pivot
|
|
238
|
-
.sortField('Region', 'asc') // Sort ascending
|
|
239
|
-
.filterField('Product', { include: ['Widget', 'Gadget'] }); // Include only these
|
|
240
|
-
|
|
241
|
-
await wb.toFile('report.xlsx');
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### Pivot Table API
|
|
245
|
-
|
|
246
|
-
```typescript
|
|
247
|
-
// Add fields to different areas
|
|
248
|
-
pivot.addRowField(fieldName: string): PivotTable
|
|
249
|
-
pivot.addColumnField(fieldName: string): PivotTable
|
|
250
|
-
pivot.addValueField(fieldName: string, aggregation?: AggregationType, displayName?: string): PivotTable
|
|
251
|
-
pivot.addFilterField(fieldName: string): PivotTable
|
|
252
|
-
|
|
253
|
-
// Aggregation types: 'sum' | 'count' | 'average' | 'min' | 'max'
|
|
254
|
-
|
|
255
|
-
// Sort a row or column field
|
|
256
|
-
pivot.sortField(fieldName: string, order: 'asc' | 'desc'): PivotTable
|
|
257
|
-
|
|
258
|
-
// Filter field values
|
|
259
|
-
pivot.filterField(fieldName: string, filter: { include?: string[] } | { exclude?: string[] }): PivotTable
|
|
260
|
-
```
|
|
261
|
-
|
|
262
168
|
## Creating Sheets from Data
|
|
263
169
|
|
|
264
170
|
Create sheets directly from arrays of objects with `addSheetFromData`:
|
|
@@ -320,7 +226,7 @@ const data = sheet.toJson();
|
|
|
320
226
|
// [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }]
|
|
321
227
|
|
|
322
228
|
// Using custom field names (first row is data, not headers)
|
|
323
|
-
const
|
|
229
|
+
const data = sheet.toJson({
|
|
324
230
|
fields: ['name', 'age', 'city'],
|
|
325
231
|
});
|
|
326
232
|
|
|
@@ -332,26 +238,21 @@ interface Person {
|
|
|
332
238
|
const people = sheet.toJson<Person>();
|
|
333
239
|
|
|
334
240
|
// Starting from a specific position
|
|
335
|
-
const
|
|
241
|
+
const data = sheet.toJson({
|
|
336
242
|
startRow: 2, // Skip first 2 rows (0-based)
|
|
337
243
|
startCol: 1, // Start from column B
|
|
338
244
|
});
|
|
339
245
|
|
|
340
246
|
// Limiting the range
|
|
341
|
-
const
|
|
247
|
+
const data = sheet.toJson({
|
|
342
248
|
endRow: 10, // Stop at row 11 (0-based, inclusive)
|
|
343
249
|
endCol: 3, // Only read columns A-D
|
|
344
250
|
});
|
|
345
251
|
|
|
346
252
|
// Continue past empty rows
|
|
347
|
-
const
|
|
253
|
+
const data = sheet.toJson({
|
|
348
254
|
stopOnEmptyRow: false, // Default is true
|
|
349
255
|
});
|
|
350
|
-
|
|
351
|
-
// Control how dates are serialized
|
|
352
|
-
const data6 = sheet.toJson({
|
|
353
|
-
dateHandling: 'isoString', // 'jsDate' | 'excelSerial' | 'isoString'
|
|
354
|
-
});
|
|
355
256
|
```
|
|
356
257
|
|
|
357
258
|
### Roundtrip Example
|
|
@@ -376,24 +277,11 @@ const readData = sheet.toJson();
|
|
|
376
277
|
## Saving
|
|
377
278
|
|
|
378
279
|
```typescript
|
|
379
|
-
//
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
// Or load from buffer
|
|
383
|
-
const buffer = await fetch('https://example.com/file.xlsx').then((r) => r.arrayBuffer());
|
|
384
|
-
const wb2 = await Workbook.fromBuffer(new Uint8Array(buffer));
|
|
385
|
-
|
|
386
|
-
// Read data
|
|
387
|
-
const sheet = wb.sheet('Sheet1');
|
|
388
|
-
console.log(sheet.cell('A1').value); // The cell value
|
|
389
|
-
console.log(sheet.cell('A1').formula); // The formula (if any)
|
|
390
|
-
console.log(sheet.cell('A1').type); // 'string' | 'number' | 'boolean' | 'date' | 'error' | 'empty'
|
|
280
|
+
// Save to file
|
|
281
|
+
await wb.toFile('output.xlsx');
|
|
391
282
|
|
|
392
|
-
//
|
|
393
|
-
const
|
|
394
|
-
if (existingCell) {
|
|
395
|
-
console.log(existingCell.value);
|
|
396
|
-
}
|
|
283
|
+
// Save to buffer (Uint8Array)
|
|
284
|
+
const buffer = await wb.toBuffer();
|
|
397
285
|
```
|
|
398
286
|
|
|
399
287
|
## Type Definitions
|
|
@@ -442,121 +330,9 @@ interface SheetToJsonConfig {
|
|
|
442
330
|
endRow?: number;
|
|
443
331
|
endCol?: number;
|
|
444
332
|
stopOnEmptyRow?: boolean; // Default: true
|
|
445
|
-
dateHandling?: 'jsDate' | 'excelSerial' | 'isoString'; // Default: 'jsDate'
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Pivot table configuration
|
|
449
|
-
interface PivotTableConfig {
|
|
450
|
-
name: string;
|
|
451
|
-
source: string; // e.g., "Sheet1!A1:D100"
|
|
452
|
-
target: string; // e.g., "Sheet2!A3"
|
|
453
|
-
refreshOnLoad?: boolean; // Default: true
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
type AggregationType = 'sum' | 'count' | 'average' | 'min' | 'max';
|
|
457
|
-
type PivotSortOrder = 'asc' | 'desc';
|
|
458
|
-
interface PivotFieldFilter {
|
|
459
|
-
include?: string[];
|
|
460
|
-
exclude?: string[];
|
|
461
333
|
}
|
|
462
334
|
```
|
|
463
335
|
|
|
464
|
-
## Address Utilities
|
|
465
|
-
|
|
466
|
-
Helper functions for working with Excel cell addresses:
|
|
467
|
-
|
|
468
|
-
```typescript
|
|
469
|
-
import {
|
|
470
|
-
colToLetter,
|
|
471
|
-
letterToCol,
|
|
472
|
-
parseAddress,
|
|
473
|
-
toAddress,
|
|
474
|
-
parseRange,
|
|
475
|
-
toRange,
|
|
476
|
-
normalizeRange,
|
|
477
|
-
isInRange,
|
|
478
|
-
} from '@niicojs/excel';
|
|
479
|
-
|
|
480
|
-
// Convert column index to letter (0-based)
|
|
481
|
-
colToLetter(0); // 'A'
|
|
482
|
-
colToLetter(25); // 'Z'
|
|
483
|
-
colToLetter(26); // 'AA'
|
|
484
|
-
|
|
485
|
-
// Convert column letter to index (0-based)
|
|
486
|
-
letterToCol('A'); // 0
|
|
487
|
-
letterToCol('Z'); // 25
|
|
488
|
-
letterToCol('AA'); // 26
|
|
489
|
-
|
|
490
|
-
// Parse cell address to row/col
|
|
491
|
-
parseAddress('B3'); // { row: 2, col: 1 }
|
|
492
|
-
parseAddress('$A$1'); // { row: 0, col: 0 } (absolute refs supported)
|
|
493
|
-
|
|
494
|
-
// Convert row/col to address
|
|
495
|
-
toAddress(0, 0); // 'A1'
|
|
496
|
-
toAddress(9, 2); // 'C10'
|
|
497
|
-
|
|
498
|
-
// Parse range string
|
|
499
|
-
parseRange('A1:C10'); // { start: { row: 0, col: 0 }, end: { row: 9, col: 2 } }
|
|
500
|
-
|
|
501
|
-
// Convert range object to string
|
|
502
|
-
toRange({ start: { row: 0, col: 0 }, end: { row: 9, col: 2 } }); // 'A1:C10'
|
|
503
|
-
|
|
504
|
-
// Normalize range (ensure start is top-left, end is bottom-right)
|
|
505
|
-
normalizeRange({ start: { row: 5, col: 3 }, end: { row: 0, col: 0 } });
|
|
506
|
-
// { start: { row: 0, col: 0 }, end: { row: 5, col: 3 } }
|
|
507
|
-
|
|
508
|
-
// Check if address is within a range
|
|
509
|
-
isInRange({ row: 2, col: 1 }, { start: { row: 0, col: 0 }, end: { row: 5, col: 5 } }); // true
|
|
510
|
-
isInRange({ row: 10, col: 0 }, { start: { row: 0, col: 0 }, end: { row: 5, col: 5 } }); // false
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
## Style Schema
|
|
514
|
-
|
|
515
|
-
Supported style properties (CellStyle):
|
|
516
|
-
|
|
517
|
-
```typescript
|
|
518
|
-
interface CellStyle {
|
|
519
|
-
bold?: boolean;
|
|
520
|
-
italic?: boolean;
|
|
521
|
-
underline?: boolean | 'single' | 'double';
|
|
522
|
-
strike?: boolean;
|
|
523
|
-
fontSize?: number;
|
|
524
|
-
fontName?: string;
|
|
525
|
-
fontColor?: string; // Hex (RGB/RRGGBB/AARRGGBB)
|
|
526
|
-
fill?: string; // Hex (RGB/RRGGBB/AARRGGBB)
|
|
527
|
-
border?: {
|
|
528
|
-
top?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
|
|
529
|
-
bottom?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
|
|
530
|
-
left?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
|
|
531
|
-
right?: 'thin' | 'medium' | 'thick' | 'double' | 'dotted' | 'dashed';
|
|
532
|
-
};
|
|
533
|
-
alignment?: {
|
|
534
|
-
horizontal?: 'left' | 'center' | 'right' | 'justify';
|
|
535
|
-
vertical?: 'top' | 'middle' | 'bottom';
|
|
536
|
-
wrapText?: boolean;
|
|
537
|
-
textRotation?: number;
|
|
538
|
-
};
|
|
539
|
-
numberFormat?: string; // Excel format code
|
|
540
|
-
}
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
## Performance and Large Files
|
|
544
|
-
|
|
545
|
-
Tips for large sheets and high-volume writes:
|
|
546
|
-
|
|
547
|
-
- Prefer `addSheetFromData` for bulk writes when possible.
|
|
548
|
-
- Use `range.getValues({ createMissing: false })` to avoid creating empty cells during reads.
|
|
549
|
-
- Keep shared strings small: prefer numbers/booleans where applicable.
|
|
550
|
-
- Avoid frequent `toBuffer()` calls in loops; batch writes and serialize once.
|
|
551
|
-
|
|
552
|
-
## Limitations
|
|
553
|
-
|
|
554
|
-
The library focuses on preserving existing structure and editing common parts of workbooks.
|
|
555
|
-
|
|
556
|
-
- Chart editing is not supported (charts are preserved only).
|
|
557
|
-
- Conditional formatting and data validation are preserved but not editable yet.
|
|
558
|
-
- Some advanced Excel features (sparklines, slicers, macros) are preserved only.
|
|
559
|
-
|
|
560
336
|
## Format Preservation
|
|
561
337
|
|
|
562
338
|
When modifying existing Excel files, this library preserves:
|