@simplysm/excel 13.0.75 → 13.0.77
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/README.md +539 -17
- package/dist/excel-cell.d.ts +4 -4
- package/dist/excel-cell.d.ts.map +1 -1
- package/dist/excel-cell.js +9 -10
- package/dist/excel-cell.js.map +1 -1
- package/dist/excel-workbook.d.ts +3 -3
- package/dist/excel-workbook.d.ts.map +1 -1
- package/dist/excel-workbook.js +3 -3
- package/dist/excel-workbook.js.map +1 -1
- package/dist/excel-worksheet.d.ts +1 -1
- package/dist/excel-worksheet.d.ts.map +1 -1
- package/dist/excel-worksheet.js +13 -17
- package/dist/excel-worksheet.js.map +1 -1
- package/dist/excel-wrapper.d.ts +1 -1
- package/dist/excel-wrapper.js +7 -7
- package/dist/excel-wrapper.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/excel-utils.d.ts +5 -5
- package/dist/utils/excel-utils.d.ts.map +1 -1
- package/dist/utils/excel-utils.js +15 -15
- package/dist/utils/excel-utils.js.map +1 -1
- package/dist/utils/zip-cache.js +3 -3
- package/dist/utils/zip-cache.js.map +1 -1
- package/dist/xml/excel-xml-relationship.js +2 -2
- package/dist/xml/excel-xml-relationship.js.map +1 -1
- package/dist/xml/excel-xml-style.js +16 -16
- package/dist/xml/excel-xml-style.js.map +1 -1
- package/dist/xml/excel-xml-workbook.js +6 -6
- package/dist/xml/excel-xml-workbook.js.map +1 -1
- package/dist/xml/excel-xml-worksheet.d.ts +5 -2
- package/dist/xml/excel-xml-worksheet.d.ts.map +1 -1
- package/dist/xml/excel-xml-worksheet.js +38 -20
- package/dist/xml/excel-xml-worksheet.js.map +1 -1
- package/package.json +2 -2
- package/src/excel-cell.ts +10 -11
- package/src/excel-workbook.ts +3 -3
- package/src/excel-worksheet.ts +17 -18
- package/src/excel-wrapper.ts +7 -7
- package/src/types.ts +1 -1
- package/src/utils/excel-utils.ts +15 -15
- package/src/utils/zip-cache.ts +3 -3
- package/src/xml/excel-xml-relationship.ts +2 -2
- package/src/xml/excel-xml-style.ts +16 -16
- package/src/xml/excel-xml-workbook.ts +6 -6
- package/src/xml/excel-xml-worksheet.ts +47 -22
- package/tests/excel-cell.spec.ts +85 -140
- package/tests/excel-col.spec.ts +17 -48
- package/tests/excel-row.spec.ts +13 -23
- package/tests/excel-workbook.spec.ts +26 -40
- package/tests/excel-worksheet.spec.ts +217 -137
- package/tests/excel-wrapper.spec.ts +24 -47
- package/tests/image-insert.spec.ts +5 -5
- package/tests/utils/excel-utils.spec.ts +14 -58
|
@@ -24,16 +24,16 @@ describe("ExcelWrapper", () => {
|
|
|
24
24
|
const ws = await wb.getWorksheet("Users");
|
|
25
25
|
|
|
26
26
|
// Check headers
|
|
27
|
-
expect(await ws.cell(0, 0).
|
|
28
|
-
expect(await ws.cell(0, 1).
|
|
29
|
-
expect(await ws.cell(0, 2).
|
|
30
|
-
expect(await ws.cell(0, 3).
|
|
27
|
+
expect(await ws.cell(0, 0).getValue()).toBe("Name");
|
|
28
|
+
expect(await ws.cell(0, 1).getValue()).toBe("Age");
|
|
29
|
+
expect(await ws.cell(0, 2).getValue()).toBe("Email");
|
|
30
|
+
expect(await ws.cell(0, 3).getValue()).toBe("Active");
|
|
31
31
|
|
|
32
32
|
// Check data
|
|
33
|
-
expect(await ws.cell(1, 0).
|
|
34
|
-
expect(await ws.cell(1, 1).
|
|
35
|
-
expect(await ws.cell(2, 0).
|
|
36
|
-
expect(await ws.cell(2, 1).
|
|
33
|
+
expect(await ws.cell(1, 0).getValue()).toBe("John Doe");
|
|
34
|
+
expect(await ws.cell(1, 1).getValue()).toBe(30);
|
|
35
|
+
expect(await ws.cell(2, 0).getValue()).toBe("Jane Smith");
|
|
36
|
+
expect(await ws.cell(2, 1).getValue()).toBe(25);
|
|
37
37
|
|
|
38
38
|
await wb.close();
|
|
39
39
|
});
|
|
@@ -65,7 +65,7 @@ describe("ExcelWrapper", () => {
|
|
|
65
65
|
];
|
|
66
66
|
|
|
67
67
|
const wb = await wrapper.write("Users", records);
|
|
68
|
-
const buffer = await wb.
|
|
68
|
+
const buffer = await wb.toBytes();
|
|
69
69
|
await wb.close();
|
|
70
70
|
|
|
71
71
|
// Read from Excel
|
|
@@ -85,7 +85,7 @@ describe("ExcelWrapper", () => {
|
|
|
85
85
|
|
|
86
86
|
const records = [{ name: "Test", age: 20 }];
|
|
87
87
|
const wb = await wrapper.write("Sheet1", records);
|
|
88
|
-
const buffer = await wb.
|
|
88
|
+
const buffer = await wb.toBytes();
|
|
89
89
|
await wb.close();
|
|
90
90
|
|
|
91
91
|
const readRecords = await wrapper.read(buffer, 0);
|
|
@@ -95,25 +95,12 @@ describe("ExcelWrapper", () => {
|
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
describe("Type conversion", () => {
|
|
98
|
-
it("can convert strings to numbers", async () => {
|
|
99
|
-
const wrapper = new ExcelWrapper(testSchema);
|
|
100
|
-
|
|
101
|
-
// Simulate Excel with values stored as strings manually
|
|
102
|
-
const wb = await wrapper.write("Test", [{ name: "Test", age: 25 }]);
|
|
103
|
-
const buffer = await wb.getBytes();
|
|
104
|
-
await wb.close();
|
|
105
|
-
|
|
106
|
-
const records = await wrapper.read(buffer);
|
|
107
|
-
expect(typeof records[0].age).toBe("number");
|
|
108
|
-
expect(records[0].age).toBe(25);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
98
|
it("applies default values", async () => {
|
|
112
99
|
const wrapper = new ExcelWrapper(testSchema);
|
|
113
100
|
|
|
114
101
|
// Save without active field
|
|
115
102
|
const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
|
|
116
|
-
const buffer = await wb.
|
|
103
|
+
const buffer = await wb.toBytes();
|
|
117
104
|
await wb.close();
|
|
118
105
|
|
|
119
106
|
const records = await wrapper.read(buffer);
|
|
@@ -133,7 +120,7 @@ describe("ExcelWrapper", () => {
|
|
|
133
120
|
const records = [{ title: "Event 1", date: new DateOnly(2024, 6, 15) }, { title: "Event 2" }];
|
|
134
121
|
|
|
135
122
|
const wb = await wrapper.write("Events", records);
|
|
136
|
-
const buffer = await wb.
|
|
123
|
+
const buffer = await wb.toBytes();
|
|
137
124
|
await wb.close();
|
|
138
125
|
|
|
139
126
|
const readRecords = await wrapper.read(buffer, "Events");
|
|
@@ -157,7 +144,7 @@ describe("ExcelWrapper", () => {
|
|
|
157
144
|
const records = [{ title: "Meeting", datetime: new DateTime(2024, 6, 15, 14, 30, 0) }];
|
|
158
145
|
|
|
159
146
|
const wb = await wrapper.write("Events", records);
|
|
160
|
-
const buffer = await wb.
|
|
147
|
+
const buffer = await wb.toBytes();
|
|
161
148
|
await wb.close();
|
|
162
149
|
|
|
163
150
|
const readRecords = await wrapper.read(buffer, "Events");
|
|
@@ -181,7 +168,7 @@ describe("ExcelWrapper", () => {
|
|
|
181
168
|
const records = [{ title: "Alarm", time: new Time(9, 30, 0) }];
|
|
182
169
|
|
|
183
170
|
const wb = await wrapper.write("Events", records);
|
|
184
|
-
const buffer = await wb.
|
|
171
|
+
const buffer = await wb.toBytes();
|
|
185
172
|
await wb.close();
|
|
186
173
|
|
|
187
174
|
const readRecords = await wrapper.read(buffer, "Events");
|
|
@@ -198,7 +185,7 @@ describe("ExcelWrapper", () => {
|
|
|
198
185
|
|
|
199
186
|
// Create empty Excel with only headers
|
|
200
187
|
const wb = await wrapper.write("Empty", []);
|
|
201
|
-
const buffer = await wb.
|
|
188
|
+
const buffer = await wb.toBytes();
|
|
202
189
|
await wb.close();
|
|
203
190
|
|
|
204
191
|
await expect(wrapper.read(buffer, "Empty")).rejects.toThrow(
|
|
@@ -210,22 +197,12 @@ describe("ExcelWrapper", () => {
|
|
|
210
197
|
const wrapper = new ExcelWrapper(testSchema);
|
|
211
198
|
|
|
212
199
|
const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
|
|
213
|
-
const buffer = await wb.
|
|
200
|
+
const buffer = await wb.toBytes();
|
|
214
201
|
await wb.close();
|
|
215
202
|
|
|
216
203
|
await expect(wrapper.read(buffer, "NotExist")).rejects.toThrow();
|
|
217
204
|
});
|
|
218
205
|
|
|
219
|
-
it("throws error when reading with non-existent worksheet index", async () => {
|
|
220
|
-
const wrapper = new ExcelWrapper(testSchema);
|
|
221
|
-
|
|
222
|
-
const wb = await wrapper.write("Test", [{ name: "Test", age: 20 }]);
|
|
223
|
-
const buffer = await wb.getBytes();
|
|
224
|
-
await wb.close();
|
|
225
|
-
|
|
226
|
-
await expect(wrapper.read(buffer, 99)).rejects.toThrow();
|
|
227
|
-
});
|
|
228
|
-
|
|
229
206
|
it("throws error with worksheet name and detailed error when schema validation fails", async () => {
|
|
230
207
|
const strictSchema = z.object({
|
|
231
208
|
name: z.string().min(5).describe("이름"), // At least 5 characters
|
|
@@ -238,9 +215,9 @@ describe("ExcelWrapper", () => {
|
|
|
238
215
|
|
|
239
216
|
// Modify data directly to trigger validation failure
|
|
240
217
|
const ws = await wb.getWorksheet("Validation");
|
|
241
|
-
await ws.cell(1, 0).
|
|
218
|
+
await ws.cell(1, 0).setValue("AB"); // Change to less than 5 characters
|
|
242
219
|
|
|
243
|
-
const buffer = await wb.
|
|
220
|
+
const buffer = await wb.toBytes();
|
|
244
221
|
await wb.close();
|
|
245
222
|
|
|
246
223
|
// Should throw validation error
|
|
@@ -264,13 +241,13 @@ describe("ExcelWrapper", () => {
|
|
|
264
241
|
const ws = await wb.getWorksheet("Test");
|
|
265
242
|
|
|
266
243
|
// Headers: only name and age exist
|
|
267
|
-
expect(await ws.cell(0, 0).
|
|
268
|
-
expect(await ws.cell(0, 1).
|
|
269
|
-
expect(await ws.cell(0, 2).
|
|
244
|
+
expect(await ws.cell(0, 0).getValue()).toBe("Name");
|
|
245
|
+
expect(await ws.cell(0, 1).getValue()).toBe("Age");
|
|
246
|
+
expect(await ws.cell(0, 2).getValue()).toBeUndefined();
|
|
270
247
|
|
|
271
248
|
// Check data
|
|
272
|
-
expect(await ws.cell(1, 0).
|
|
273
|
-
expect(await ws.cell(1, 1).
|
|
249
|
+
expect(await ws.cell(1, 0).getValue()).toBe("John Doe");
|
|
250
|
+
expect(await ws.cell(1, 1).getValue()).toBe(30);
|
|
274
251
|
|
|
275
252
|
await wb.close();
|
|
276
253
|
});
|
|
@@ -281,7 +258,7 @@ describe("ExcelWrapper", () => {
|
|
|
281
258
|
// Create Excel with all fields
|
|
282
259
|
const records = [{ name: "John Doe", age: 30, email: "john@test.com", phone: "010-1234-5678" }];
|
|
283
260
|
const wb = await wrapper.write("Test", records);
|
|
284
|
-
const buffer = await wb.
|
|
261
|
+
const buffer = await wb.toBytes();
|
|
285
262
|
await wb.close();
|
|
286
263
|
|
|
287
264
|
// Read with excludes
|
|
@@ -33,7 +33,7 @@ async function loadPngFile(): Promise<Uint8Array> {
|
|
|
33
33
|
describe("ExcelWorksheet.addImage integration", () => {
|
|
34
34
|
it("should write media, drawing, drawing rels, worksheet rel and content types", async () => {
|
|
35
35
|
const wb = new ExcelWorkbook();
|
|
36
|
-
const ws = await wb.
|
|
36
|
+
const ws = await wb.addWorksheet("Sheet1");
|
|
37
37
|
|
|
38
38
|
const bytes = await loadPngFile();
|
|
39
39
|
|
|
@@ -102,14 +102,14 @@ describe("ExcelWorksheet.addImage integration", () => {
|
|
|
102
102
|
expect(drawingElems.some((d: any) => d.$ != null && d.$["r:id"] != null)).toBeTruthy();
|
|
103
103
|
|
|
104
104
|
// Verify buffer creation
|
|
105
|
-
const resultBuffer = await wb.
|
|
105
|
+
const resultBuffer = await wb.toBytes();
|
|
106
106
|
expect(resultBuffer).toBeDefined();
|
|
107
107
|
expect(resultBuffer.length).toBeGreaterThan(0);
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
it("can insert multiple images into the same worksheet", async () => {
|
|
111
111
|
const wb = new ExcelWorkbook();
|
|
112
|
-
const ws = await wb.
|
|
112
|
+
const ws = await wb.addWorksheet("Sheet1");
|
|
113
113
|
|
|
114
114
|
const bytes = await loadPngFile();
|
|
115
115
|
|
|
@@ -170,14 +170,14 @@ describe("ExcelWorksheet.addImage integration", () => {
|
|
|
170
170
|
expect(relsArr.some((r: any) => r.$.Target === "../media/image2.png")).toBeTruthy();
|
|
171
171
|
|
|
172
172
|
// Verify buffer creation
|
|
173
|
-
const resultBuffer = await wb.
|
|
173
|
+
const resultBuffer = await wb.toBytes();
|
|
174
174
|
expect(resultBuffer).toBeDefined();
|
|
175
175
|
expect(resultBuffer.length).toBeGreaterThan(0);
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
it("throws error for unsupported file extensions", async () => {
|
|
179
179
|
const wb = new ExcelWorkbook();
|
|
180
|
-
const ws = await wb.
|
|
180
|
+
const ws = await wb.addWorksheet("Sheet1");
|
|
181
181
|
|
|
182
182
|
await expect(
|
|
183
183
|
ws.addImage({
|
|
@@ -2,13 +2,7 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import { ExcelUtils } from "../../src/utils/excel-utils";
|
|
3
3
|
|
|
4
4
|
describe("ExcelUtils", () => {
|
|
5
|
-
describe("stringifyColAddr /
|
|
6
|
-
it("converts 0-25 to A-Z", () => {
|
|
7
|
-
expect(ExcelUtils.stringifyColAddr(0)).toBe("A");
|
|
8
|
-
expect(ExcelUtils.stringifyColAddr(1)).toBe("B");
|
|
9
|
-
expect(ExcelUtils.stringifyColAddr(25)).toBe("Z");
|
|
10
|
-
});
|
|
11
|
-
|
|
5
|
+
describe("stringifyColAddr / parseColAddr", () => {
|
|
12
6
|
it("converts 26 and above to AA, AB, etc.", () => {
|
|
13
7
|
expect(ExcelUtils.stringifyColAddr(26)).toBe("AA");
|
|
14
8
|
expect(ExcelUtils.stringifyColAddr(27)).toBe("AB");
|
|
@@ -24,32 +18,13 @@ describe("ExcelUtils", () => {
|
|
|
24
18
|
it("handles Excel maximum column index (XFD, 16383)", () => {
|
|
25
19
|
// Excel maximum column is XFD (index 16383, 0-based)
|
|
26
20
|
expect(ExcelUtils.stringifyColAddr(16383)).toBe("XFD");
|
|
27
|
-
expect(ExcelUtils.
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("parses A-Z to 0-25", () => {
|
|
31
|
-
expect(ExcelUtils.parseColAddrCode("A")).toBe(0);
|
|
32
|
-
expect(ExcelUtils.parseColAddrCode("B")).toBe(1);
|
|
33
|
-
expect(ExcelUtils.parseColAddrCode("Z")).toBe(25);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("parses AA, AB, etc. to 26 and above", () => {
|
|
37
|
-
expect(ExcelUtils.parseColAddrCode("AA")).toBe(26);
|
|
38
|
-
expect(ExcelUtils.parseColAddrCode("AB")).toBe(27);
|
|
39
|
-
expect(ExcelUtils.parseColAddrCode("AZ")).toBe(51);
|
|
40
|
-
expect(ExcelUtils.parseColAddrCode("BA")).toBe(52);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("parses column index from cell address", () => {
|
|
44
|
-
expect(ExcelUtils.parseColAddrCode("A1")).toBe(0);
|
|
45
|
-
expect(ExcelUtils.parseColAddrCode("B10")).toBe(1);
|
|
46
|
-
expect(ExcelUtils.parseColAddrCode("AA100")).toBe(26);
|
|
21
|
+
expect(ExcelUtils.parseColAddr("XFD")).toBe(16383);
|
|
47
22
|
});
|
|
48
23
|
|
|
49
24
|
it("round-trip: stringify → parse returns original value", () => {
|
|
50
25
|
for (let i = 0; i < 100; i++) {
|
|
51
26
|
const stringified = ExcelUtils.stringifyColAddr(i);
|
|
52
|
-
const parsed = ExcelUtils.
|
|
27
|
+
const parsed = ExcelUtils.parseColAddr(stringified);
|
|
53
28
|
expect(parsed).toBe(i);
|
|
54
29
|
}
|
|
55
30
|
});
|
|
@@ -60,7 +35,7 @@ describe("ExcelUtils", () => {
|
|
|
60
35
|
});
|
|
61
36
|
});
|
|
62
37
|
|
|
63
|
-
describe("stringifyRowAddr /
|
|
38
|
+
describe("stringifyRowAddr / parseRowAddr", () => {
|
|
64
39
|
it("converts 0-based index to 1-based string", () => {
|
|
65
40
|
expect(ExcelUtils.stringifyRowAddr(0)).toBe("1");
|
|
66
41
|
expect(ExcelUtils.stringifyRowAddr(9)).toBe("10");
|
|
@@ -68,13 +43,13 @@ describe("ExcelUtils", () => {
|
|
|
68
43
|
});
|
|
69
44
|
|
|
70
45
|
it("parses 1-based string to 0-based index", () => {
|
|
71
|
-
expect(ExcelUtils.
|
|
72
|
-
expect(ExcelUtils.
|
|
73
|
-
expect(ExcelUtils.
|
|
46
|
+
expect(ExcelUtils.parseRowAddr("A1")).toBe(0);
|
|
47
|
+
expect(ExcelUtils.parseRowAddr("B10")).toBe(9);
|
|
48
|
+
expect(ExcelUtils.parseRowAddr("AA100")).toBe(99);
|
|
74
49
|
});
|
|
75
50
|
});
|
|
76
51
|
|
|
77
|
-
describe("stringifyAddr /
|
|
52
|
+
describe("stringifyAddr / parseCellAddr", () => {
|
|
78
53
|
it("correctly converts cell address", () => {
|
|
79
54
|
expect(ExcelUtils.stringifyAddr({ r: 0, c: 0 })).toBe("A1");
|
|
80
55
|
expect(ExcelUtils.stringifyAddr({ r: 9, c: 1 })).toBe("B10");
|
|
@@ -82,21 +57,21 @@ describe("ExcelUtils", () => {
|
|
|
82
57
|
});
|
|
83
58
|
|
|
84
59
|
it("correctly parses cell address", () => {
|
|
85
|
-
expect(ExcelUtils.
|
|
86
|
-
expect(ExcelUtils.
|
|
87
|
-
expect(ExcelUtils.
|
|
60
|
+
expect(ExcelUtils.parseCellAddr("A1")).toEqual({ r: 0, c: 0 });
|
|
61
|
+
expect(ExcelUtils.parseCellAddr("B10")).toEqual({ r: 9, c: 1 });
|
|
62
|
+
expect(ExcelUtils.parseCellAddr("AA100")).toEqual({ r: 99, c: 26 });
|
|
88
63
|
});
|
|
89
64
|
});
|
|
90
65
|
|
|
91
|
-
describe("
|
|
66
|
+
describe("parseRangeAddr / stringifyRangeAddr", () => {
|
|
92
67
|
it("parses single cell range", () => {
|
|
93
|
-
const range = ExcelUtils.
|
|
68
|
+
const range = ExcelUtils.parseRangeAddr("A1");
|
|
94
69
|
expect(range.s).toEqual({ r: 0, c: 0 });
|
|
95
70
|
expect(range.e).toEqual({ r: 0, c: 0 });
|
|
96
71
|
});
|
|
97
72
|
|
|
98
73
|
it("parses multi-cell range", () => {
|
|
99
|
-
const range = ExcelUtils.
|
|
74
|
+
const range = ExcelUtils.parseRangeAddr("A1:C3");
|
|
100
75
|
expect(range.s).toEqual({ r: 0, c: 0 });
|
|
101
76
|
expect(range.e).toEqual({ r: 2, c: 2 });
|
|
102
77
|
});
|
|
@@ -127,25 +102,6 @@ describe("ExcelUtils", () => {
|
|
|
127
102
|
expect(excelNum).toBeCloseTo(25569, 0);
|
|
128
103
|
});
|
|
129
104
|
|
|
130
|
-
it("correctly converts 2024-06-15", () => {
|
|
131
|
-
const date = new Date(Date.UTC(2024, 5, 15, 0, 0, 0));
|
|
132
|
-
const tick = date.getTime();
|
|
133
|
-
const excelNum = ExcelUtils.convertTimeTickToNumber(tick);
|
|
134
|
-
// Verify approximate value
|
|
135
|
-
expect(excelNum).toBeGreaterThan(45000);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("correctly converts date with time", () => {
|
|
139
|
-
const date = new Date(Date.UTC(2024, 5, 15, 12, 0, 0));
|
|
140
|
-
const tick = date.getTime();
|
|
141
|
-
const excelNum = ExcelUtils.convertTimeTickToNumber(tick);
|
|
142
|
-
// 12:00 = 0.5 days additional
|
|
143
|
-
const baseNum = ExcelUtils.convertTimeTickToNumber(
|
|
144
|
-
new Date(Date.UTC(2024, 5, 15, 0, 0, 0)).getTime(),
|
|
145
|
-
);
|
|
146
|
-
expect(excelNum - baseNum).toBeCloseTo(0.5, 1);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
105
|
it("round-trip: tick → number → tick returns original value", () => {
|
|
150
106
|
const originalDate = new Date(Date.UTC(2024, 5, 15, 14, 30, 45));
|
|
151
107
|
const tick = originalDate.getTime();
|