@niicojs/excel 0.3.1 → 0.3.3
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 +585 -585
- package/dist/index.cjs +1004 -438
- package/dist/index.d.cts +53 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1005 -439
- package/package.json +3 -3
- package/src/cell.ts +20 -6
- package/src/index.ts +45 -45
- package/src/pivot-cache.ts +501 -300
- package/src/pivot-table.ts +680 -684
- package/src/range.ts +154 -154
- package/src/shared-strings.ts +185 -178
- package/src/styles.ts +819 -819
- package/src/table.ts +386 -386
- package/src/types.ts +54 -36
- package/src/utils/address.ts +121 -121
- package/src/utils/format.ts +356 -0
- package/src/utils/xml.ts +153 -140
- package/src/utils/zip.ts +29 -5
- package/src/workbook.ts +1412 -1390
- package/src/worksheet.ts +85 -84
package/src/types.ts
CHANGED
|
@@ -158,36 +158,48 @@ export interface PivotValueConfig {
|
|
|
158
158
|
/**
|
|
159
159
|
* Configuration for creating a pivot table
|
|
160
160
|
*/
|
|
161
|
-
export interface PivotTableConfig {
|
|
162
|
-
/** Name of the pivot table */
|
|
163
|
-
name: string;
|
|
164
|
-
/** Source data range with sheet name (e.g., "Sheet1!A1:D100") */
|
|
165
|
-
source: string;
|
|
166
|
-
/** Target cell where pivot table will be placed (e.g., "Sheet2!A3") */
|
|
167
|
-
target: string;
|
|
168
|
-
/** Refresh the pivot table data when the file is opened (default: true) */
|
|
169
|
-
refreshOnLoad?: boolean;
|
|
170
|
-
|
|
161
|
+
export interface PivotTableConfig {
|
|
162
|
+
/** Name of the pivot table */
|
|
163
|
+
name: string;
|
|
164
|
+
/** Source data range with sheet name (e.g., "Sheet1!A1:D100") */
|
|
165
|
+
source: string;
|
|
166
|
+
/** Target cell where pivot table will be placed (e.g., "Sheet2!A3") */
|
|
167
|
+
target: string;
|
|
168
|
+
/** Refresh the pivot table data when the file is opened (default: true) */
|
|
169
|
+
refreshOnLoad?: boolean;
|
|
170
|
+
/** Save pivot cache data in the file (default: true) */
|
|
171
|
+
saveData?: boolean;
|
|
172
|
+
}
|
|
171
173
|
|
|
172
174
|
/**
|
|
173
175
|
* Internal representation of a pivot cache field
|
|
174
176
|
*/
|
|
175
|
-
export interface PivotCacheField {
|
|
176
|
-
/** Field name (from header row) */
|
|
177
|
-
name: string;
|
|
178
|
-
/** Field index (0-based) */
|
|
179
|
-
index: number;
|
|
180
|
-
/** Whether this field contains numbers */
|
|
181
|
-
isNumeric: boolean;
|
|
182
|
-
/** Whether this field contains dates */
|
|
183
|
-
isDate: boolean;
|
|
184
|
-
/**
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
|
|
190
|
-
|
|
177
|
+
export interface PivotCacheField {
|
|
178
|
+
/** Field name (from header row) */
|
|
179
|
+
name: string;
|
|
180
|
+
/** Field index (0-based) */
|
|
181
|
+
index: number;
|
|
182
|
+
/** Whether this field contains numbers */
|
|
183
|
+
isNumeric: boolean;
|
|
184
|
+
/** Whether this field contains dates */
|
|
185
|
+
isDate: boolean;
|
|
186
|
+
/** Whether this field contains boolean values */
|
|
187
|
+
hasBoolean: boolean;
|
|
188
|
+
/** Whether this field contains blank (null/undefined) values */
|
|
189
|
+
hasBlank: boolean;
|
|
190
|
+
/** Number format ID for this field (cache field numFmtId) */
|
|
191
|
+
numFmtId?: number;
|
|
192
|
+
/** Unique string values (for shared items) */
|
|
193
|
+
sharedItems: string[];
|
|
194
|
+
/** Min numeric value */
|
|
195
|
+
minValue?: number;
|
|
196
|
+
/** Max numeric value */
|
|
197
|
+
maxValue?: number;
|
|
198
|
+
/** Min date value (for date fields) */
|
|
199
|
+
minDate?: Date;
|
|
200
|
+
/** Max date value (for date fields) */
|
|
201
|
+
maxDate?: Date;
|
|
202
|
+
}
|
|
191
203
|
|
|
192
204
|
/**
|
|
193
205
|
* Pivot field axis assignment
|
|
@@ -305,19 +317,25 @@ export interface SheetToJsonConfig {
|
|
|
305
317
|
*/
|
|
306
318
|
endCol?: number;
|
|
307
319
|
|
|
308
|
-
/**
|
|
309
|
-
* If true, stop reading when an empty row is encountered. Defaults to true.
|
|
310
|
-
*/
|
|
311
|
-
stopOnEmptyRow?: boolean;
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* How to serialize Date values. Defaults to 'jsDate'.
|
|
315
|
-
*/
|
|
316
|
-
dateHandling?: DateHandling;
|
|
317
|
-
|
|
320
|
+
/**
|
|
321
|
+
* If true, stop reading when an empty row is encountered. Defaults to true.
|
|
322
|
+
*/
|
|
323
|
+
stopOnEmptyRow?: boolean;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* How to serialize Date values. Defaults to 'jsDate'.
|
|
327
|
+
*/
|
|
328
|
+
dateHandling?: DateHandling;
|
|
329
|
+
|
|
318
330
|
/**
|
|
319
331
|
* If true, return formatted text (as displayed in Excel) instead of raw values.
|
|
320
332
|
* All values will be returned as strings. Defaults to false.
|
|
321
333
|
*/
|
|
322
334
|
asText?: boolean;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Locale to use for formatting when asText is true.
|
|
338
|
+
* Defaults to the workbook locale.
|
|
339
|
+
*/
|
|
340
|
+
locale?: string;
|
|
323
341
|
}
|
package/src/utils/address.ts
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
import type { CellAddress, RangeAddress } from '../types';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Converts a column index (0-based) to Excel column letters (A, B, ..., Z, AA, AB, ...)
|
|
5
|
-
* @param col - 0-based column index
|
|
6
|
-
* @returns Column letter(s)
|
|
7
|
-
*/
|
|
8
|
-
export const colToLetter = (col: number): string => {
|
|
9
|
-
let result = '';
|
|
10
|
-
let n = col;
|
|
11
|
-
while (n >= 0) {
|
|
12
|
-
result = String.fromCharCode((n % 26) + 65) + result;
|
|
13
|
-
n = Math.floor(n / 26) - 1;
|
|
14
|
-
}
|
|
15
|
-
return result;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Converts Excel column letters to a 0-based column index
|
|
20
|
-
* @param letters - Column letter(s) like 'A', 'B', 'AA'
|
|
21
|
-
* @returns 0-based column index
|
|
22
|
-
*/
|
|
23
|
-
export const letterToCol = (letters: string): number => {
|
|
24
|
-
const upper = letters.toUpperCase();
|
|
25
|
-
let col = 0;
|
|
26
|
-
for (let i = 0; i < upper.length; i++) {
|
|
27
|
-
col = col * 26 + (upper.charCodeAt(i) - 64);
|
|
28
|
-
}
|
|
29
|
-
return col - 1;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Parses an Excel cell address (e.g., 'A1', '$B$2') to row/col indices
|
|
34
|
-
* @param address - Cell address string
|
|
35
|
-
* @returns CellAddress with 0-based row and col
|
|
36
|
-
*/
|
|
37
|
-
export const parseAddress = (address: string): CellAddress => {
|
|
38
|
-
// Remove $ signs for absolute references
|
|
39
|
-
const clean = address.replace(/\$/g, '');
|
|
40
|
-
const match = clean.match(/^([A-Z]+)(\d+)$/i);
|
|
41
|
-
if (!match) {
|
|
42
|
-
throw new Error(`Invalid cell address: ${address}`);
|
|
43
|
-
}
|
|
44
|
-
const rowNumber = +match[2];
|
|
45
|
-
if (rowNumber <= 0) throw new Error(`Invalid cell address: ${address}`);
|
|
46
|
-
|
|
47
|
-
const col = letterToCol(match[1].toUpperCase());
|
|
48
|
-
const row = rowNumber - 1; // Convert to 0-based
|
|
49
|
-
return { row, col };
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Converts row/col indices to an Excel cell address
|
|
54
|
-
* @param row - 0-based row index
|
|
55
|
-
* @param col - 0-based column index
|
|
56
|
-
* @returns Cell address string like 'A1'
|
|
57
|
-
*/
|
|
58
|
-
export const toAddress = (row: number, col: number): string => {
|
|
59
|
-
return `${colToLetter(col)}${row + 1}`;
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Parses an Excel range (e.g., 'A1:B10') to start/end addresses
|
|
64
|
-
* @param range - Range string
|
|
65
|
-
* @returns RangeAddress with start and end
|
|
66
|
-
*/
|
|
67
|
-
export const parseRange = (range: string): RangeAddress => {
|
|
68
|
-
const parts = range.split(':');
|
|
69
|
-
if (parts.length === 1) {
|
|
70
|
-
// Single cell range
|
|
71
|
-
const addr = parseAddress(parts[0]);
|
|
72
|
-
return { start: addr, end: addr };
|
|
73
|
-
}
|
|
74
|
-
if (parts.length !== 2) {
|
|
75
|
-
throw new Error(`Invalid range: ${range}`);
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
start: parseAddress(parts[0]),
|
|
79
|
-
end: parseAddress(parts[1]),
|
|
80
|
-
};
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Converts a RangeAddress to a range string
|
|
85
|
-
* @param range - RangeAddress object
|
|
86
|
-
* @returns Range string like 'A1:B10'
|
|
87
|
-
*/
|
|
88
|
-
export const toRange = (range: RangeAddress): string => {
|
|
89
|
-
const start = toAddress(range.start.row, range.start.col);
|
|
90
|
-
const end = toAddress(range.end.row, range.end.col);
|
|
91
|
-
if (start === end) {
|
|
92
|
-
return start;
|
|
93
|
-
}
|
|
94
|
-
return `${start}:${end}`;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Normalizes a range so start is always top-left and end is bottom-right
|
|
99
|
-
*/
|
|
100
|
-
export const normalizeRange = (range: RangeAddress): RangeAddress => {
|
|
101
|
-
return {
|
|
102
|
-
start: {
|
|
103
|
-
row: Math.min(range.start.row, range.end.row),
|
|
104
|
-
col: Math.min(range.start.col, range.end.col),
|
|
105
|
-
},
|
|
106
|
-
end: {
|
|
107
|
-
row: Math.max(range.start.row, range.end.row),
|
|
108
|
-
col: Math.max(range.start.col, range.end.col),
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Checks if an address is within a range
|
|
115
|
-
*/
|
|
116
|
-
export const isInRange = (addr: CellAddress, range: RangeAddress): boolean => {
|
|
117
|
-
const norm = normalizeRange(range);
|
|
118
|
-
return (
|
|
119
|
-
addr.row >= norm.start.row && addr.row <= norm.end.row && addr.col >= norm.start.col && addr.col <= norm.end.col
|
|
120
|
-
);
|
|
121
|
-
};
|
|
1
|
+
import type { CellAddress, RangeAddress } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a column index (0-based) to Excel column letters (A, B, ..., Z, AA, AB, ...)
|
|
5
|
+
* @param col - 0-based column index
|
|
6
|
+
* @returns Column letter(s)
|
|
7
|
+
*/
|
|
8
|
+
export const colToLetter = (col: number): string => {
|
|
9
|
+
let result = '';
|
|
10
|
+
let n = col;
|
|
11
|
+
while (n >= 0) {
|
|
12
|
+
result = String.fromCharCode((n % 26) + 65) + result;
|
|
13
|
+
n = Math.floor(n / 26) - 1;
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Converts Excel column letters to a 0-based column index
|
|
20
|
+
* @param letters - Column letter(s) like 'A', 'B', 'AA'
|
|
21
|
+
* @returns 0-based column index
|
|
22
|
+
*/
|
|
23
|
+
export const letterToCol = (letters: string): number => {
|
|
24
|
+
const upper = letters.toUpperCase();
|
|
25
|
+
let col = 0;
|
|
26
|
+
for (let i = 0; i < upper.length; i++) {
|
|
27
|
+
col = col * 26 + (upper.charCodeAt(i) - 64);
|
|
28
|
+
}
|
|
29
|
+
return col - 1;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parses an Excel cell address (e.g., 'A1', '$B$2') to row/col indices
|
|
34
|
+
* @param address - Cell address string
|
|
35
|
+
* @returns CellAddress with 0-based row and col
|
|
36
|
+
*/
|
|
37
|
+
export const parseAddress = (address: string): CellAddress => {
|
|
38
|
+
// Remove $ signs for absolute references
|
|
39
|
+
const clean = address.replace(/\$/g, '');
|
|
40
|
+
const match = clean.match(/^([A-Z]+)(\d+)$/i);
|
|
41
|
+
if (!match) {
|
|
42
|
+
throw new Error(`Invalid cell address: ${address}`);
|
|
43
|
+
}
|
|
44
|
+
const rowNumber = +match[2];
|
|
45
|
+
if (rowNumber <= 0) throw new Error(`Invalid cell address: ${address}`);
|
|
46
|
+
|
|
47
|
+
const col = letterToCol(match[1].toUpperCase());
|
|
48
|
+
const row = rowNumber - 1; // Convert to 0-based
|
|
49
|
+
return { row, col };
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Converts row/col indices to an Excel cell address
|
|
54
|
+
* @param row - 0-based row index
|
|
55
|
+
* @param col - 0-based column index
|
|
56
|
+
* @returns Cell address string like 'A1'
|
|
57
|
+
*/
|
|
58
|
+
export const toAddress = (row: number, col: number): string => {
|
|
59
|
+
return `${colToLetter(col)}${row + 1}`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Parses an Excel range (e.g., 'A1:B10') to start/end addresses
|
|
64
|
+
* @param range - Range string
|
|
65
|
+
* @returns RangeAddress with start and end
|
|
66
|
+
*/
|
|
67
|
+
export const parseRange = (range: string): RangeAddress => {
|
|
68
|
+
const parts = range.split(':');
|
|
69
|
+
if (parts.length === 1) {
|
|
70
|
+
// Single cell range
|
|
71
|
+
const addr = parseAddress(parts[0]);
|
|
72
|
+
return { start: addr, end: addr };
|
|
73
|
+
}
|
|
74
|
+
if (parts.length !== 2) {
|
|
75
|
+
throw new Error(`Invalid range: ${range}`);
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
start: parseAddress(parts[0]),
|
|
79
|
+
end: parseAddress(parts[1]),
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Converts a RangeAddress to a range string
|
|
85
|
+
* @param range - RangeAddress object
|
|
86
|
+
* @returns Range string like 'A1:B10'
|
|
87
|
+
*/
|
|
88
|
+
export const toRange = (range: RangeAddress): string => {
|
|
89
|
+
const start = toAddress(range.start.row, range.start.col);
|
|
90
|
+
const end = toAddress(range.end.row, range.end.col);
|
|
91
|
+
if (start === end) {
|
|
92
|
+
return start;
|
|
93
|
+
}
|
|
94
|
+
return `${start}:${end}`;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Normalizes a range so start is always top-left and end is bottom-right
|
|
99
|
+
*/
|
|
100
|
+
export const normalizeRange = (range: RangeAddress): RangeAddress => {
|
|
101
|
+
return {
|
|
102
|
+
start: {
|
|
103
|
+
row: Math.min(range.start.row, range.end.row),
|
|
104
|
+
col: Math.min(range.start.col, range.end.col),
|
|
105
|
+
},
|
|
106
|
+
end: {
|
|
107
|
+
row: Math.max(range.start.row, range.end.row),
|
|
108
|
+
col: Math.max(range.start.col, range.end.col),
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Checks if an address is within a range
|
|
115
|
+
*/
|
|
116
|
+
export const isInRange = (addr: CellAddress, range: RangeAddress): boolean => {
|
|
117
|
+
const norm = normalizeRange(range);
|
|
118
|
+
return (
|
|
119
|
+
addr.row >= norm.start.row && addr.row <= norm.end.row && addr.col >= norm.start.col && addr.col <= norm.end.col
|
|
120
|
+
);
|
|
121
|
+
};
|