@simplysm/excel 13.0.69 → 13.0.70

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 (74) hide show
  1. package/README.md +19 -516
  2. package/dist/excel-cell.d.ts +28 -28
  3. package/dist/excel-cell.d.ts.map +1 -1
  4. package/dist/excel-cell.js +24 -24
  5. package/dist/excel-cell.js.map +1 -1
  6. package/dist/excel-col.d.ts +4 -4
  7. package/dist/excel-col.d.ts.map +1 -1
  8. package/dist/excel-col.js +3 -3
  9. package/dist/excel-row.d.ts +3 -3
  10. package/dist/excel-row.d.ts.map +1 -1
  11. package/dist/excel-row.js +2 -2
  12. package/dist/excel-workbook.d.ts +23 -23
  13. package/dist/excel-workbook.d.ts.map +1 -1
  14. package/dist/excel-workbook.js +15 -15
  15. package/dist/excel-workbook.js.map +1 -1
  16. package/dist/excel-worksheet.d.ts +32 -32
  17. package/dist/excel-worksheet.d.ts.map +1 -1
  18. package/dist/excel-worksheet.js +32 -32
  19. package/dist/excel-worksheet.js.map +1 -1
  20. package/dist/excel-wrapper.d.ts +7 -7
  21. package/dist/excel-wrapper.js +7 -7
  22. package/dist/excel-wrapper.js.map +1 -1
  23. package/dist/types.d.ts +16 -16
  24. package/dist/types.d.ts.map +1 -1
  25. package/dist/utils/excel-utils.d.ts +23 -23
  26. package/dist/utils/excel-utils.d.ts.map +1 -1
  27. package/dist/utils/excel-utils.js +25 -25
  28. package/dist/utils/excel-utils.js.map +1 -1
  29. package/dist/utils/zip-cache.d.ts +6 -6
  30. package/dist/xml/excel-xml-content-type.d.ts +2 -2
  31. package/dist/xml/excel-xml-drawing.d.ts +2 -2
  32. package/dist/xml/excel-xml-relationship.d.ts +2 -2
  33. package/dist/xml/excel-xml-relationship.js +1 -1
  34. package/dist/xml/excel-xml-relationship.js.map +1 -1
  35. package/dist/xml/excel-xml-shared-string.d.ts +2 -2
  36. package/dist/xml/excel-xml-style.d.ts +2 -2
  37. package/dist/xml/excel-xml-style.js +6 -6
  38. package/dist/xml/excel-xml-style.js.map +1 -1
  39. package/dist/xml/excel-xml-unknown.d.ts +2 -2
  40. package/dist/xml/excel-xml-workbook.d.ts +2 -2
  41. package/dist/xml/excel-xml-workbook.js +1 -1
  42. package/dist/xml/excel-xml-workbook.js.map +1 -1
  43. package/dist/xml/excel-xml-worksheet.d.ts +6 -6
  44. package/dist/xml/excel-xml-worksheet.d.ts.map +1 -1
  45. package/dist/xml/excel-xml-worksheet.js +9 -8
  46. package/dist/xml/excel-xml-worksheet.js.map +1 -1
  47. package/package.json +6 -5
  48. package/src/excel-cell.ts +35 -35
  49. package/src/excel-col.ts +4 -4
  50. package/src/excel-row.ts +3 -3
  51. package/src/excel-workbook.ts +30 -30
  52. package/src/excel-worksheet.ts +47 -47
  53. package/src/excel-wrapper.ts +18 -18
  54. package/src/index.ts +3 -3
  55. package/src/types.ts +15 -17
  56. package/src/utils/excel-utils.ts +38 -38
  57. package/src/utils/zip-cache.ts +6 -6
  58. package/src/xml/excel-xml-content-type.ts +3 -3
  59. package/src/xml/excel-xml-drawing.ts +2 -2
  60. package/src/xml/excel-xml-relationship.ts +3 -3
  61. package/src/xml/excel-xml-shared-string.ts +2 -2
  62. package/src/xml/excel-xml-style.ts +11 -11
  63. package/src/xml/excel-xml-unknown.ts +2 -2
  64. package/src/xml/excel-xml-workbook.ts +5 -5
  65. package/src/xml/excel-xml-worksheet.ts +44 -43
  66. package/tests/excel-cell.spec.ts +448 -0
  67. package/tests/excel-col.spec.ts +112 -0
  68. package/tests/excel-row.spec.ts +71 -0
  69. package/tests/excel-workbook.spec.ts +160 -0
  70. package/tests/excel-worksheet.spec.ts +389 -0
  71. package/tests/excel-wrapper.spec.ts +296 -0
  72. package/tests/fixtures/logo.png +0 -0
  73. package/tests/image-insert.spec.ts +190 -0
  74. package/tests/utils/excel-utils.spec.ts +242 -0
@@ -0,0 +1,242 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ExcelUtils } from "../../src/utils/excel-utils";
3
+
4
+ describe("ExcelUtils", () => {
5
+ describe("stringifyColAddr / parseColAddrCode", () => {
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
+
12
+ it("converts 26 and above to AA, AB, etc.", () => {
13
+ expect(ExcelUtils.stringifyColAddr(26)).toBe("AA");
14
+ expect(ExcelUtils.stringifyColAddr(27)).toBe("AB");
15
+ expect(ExcelUtils.stringifyColAddr(51)).toBe("AZ");
16
+ expect(ExcelUtils.stringifyColAddr(52)).toBe("BA");
17
+ });
18
+
19
+ it("handles large column indices", () => {
20
+ // 702 = AAA (26^2 + 26 = 702)
21
+ expect(ExcelUtils.stringifyColAddr(702)).toBe("AAA");
22
+ });
23
+
24
+ it("handles Excel maximum column index (XFD, 16383)", () => {
25
+ // Excel maximum column is XFD (index 16383, 0-based)
26
+ expect(ExcelUtils.stringifyColAddr(16383)).toBe("XFD");
27
+ expect(ExcelUtils.parseColAddrCode("XFD")).toBe(16383);
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);
47
+ });
48
+
49
+ it("round-trip: stringify → parse returns original value", () => {
50
+ for (let i = 0; i < 100; i++) {
51
+ const stringified = ExcelUtils.stringifyColAddr(i);
52
+ const parsed = ExcelUtils.parseColAddrCode(stringified);
53
+ expect(parsed).toBe(i);
54
+ }
55
+ });
56
+
57
+ it("throws error on negative column index input", () => {
58
+ expect(() => ExcelUtils.stringifyColAddr(-1)).toThrow();
59
+ expect(() => ExcelUtils.stringifyColAddr(-100)).toThrow();
60
+ });
61
+ });
62
+
63
+ describe("stringifyRowAddr / parseRowAddrCode", () => {
64
+ it("converts 0-based index to 1-based string", () => {
65
+ expect(ExcelUtils.stringifyRowAddr(0)).toBe("1");
66
+ expect(ExcelUtils.stringifyRowAddr(9)).toBe("10");
67
+ expect(ExcelUtils.stringifyRowAddr(99)).toBe("100");
68
+ });
69
+
70
+ it("parses 1-based string to 0-based index", () => {
71
+ expect(ExcelUtils.parseRowAddrCode("A1")).toBe(0);
72
+ expect(ExcelUtils.parseRowAddrCode("B10")).toBe(9);
73
+ expect(ExcelUtils.parseRowAddrCode("AA100")).toBe(99);
74
+ });
75
+ });
76
+
77
+ describe("stringifyAddr / parseCellAddrCode", () => {
78
+ it("correctly converts cell address", () => {
79
+ expect(ExcelUtils.stringifyAddr({ r: 0, c: 0 })).toBe("A1");
80
+ expect(ExcelUtils.stringifyAddr({ r: 9, c: 1 })).toBe("B10");
81
+ expect(ExcelUtils.stringifyAddr({ r: 99, c: 26 })).toBe("AA100");
82
+ });
83
+
84
+ it("correctly parses cell address", () => {
85
+ expect(ExcelUtils.parseCellAddrCode("A1")).toEqual({ r: 0, c: 0 });
86
+ expect(ExcelUtils.parseCellAddrCode("B10")).toEqual({ r: 9, c: 1 });
87
+ expect(ExcelUtils.parseCellAddrCode("AA100")).toEqual({ r: 99, c: 26 });
88
+ });
89
+ });
90
+
91
+ describe("parseRangeAddrCode / stringifyRangeAddr", () => {
92
+ it("parses single cell range", () => {
93
+ const range = ExcelUtils.parseRangeAddrCode("A1");
94
+ expect(range.s).toEqual({ r: 0, c: 0 });
95
+ expect(range.e).toEqual({ r: 0, c: 0 });
96
+ });
97
+
98
+ it("parses multi-cell range", () => {
99
+ const range = ExcelUtils.parseRangeAddrCode("A1:C3");
100
+ expect(range.s).toEqual({ r: 0, c: 0 });
101
+ expect(range.e).toEqual({ r: 2, c: 2 });
102
+ });
103
+
104
+ it("converts single cell range to string", () => {
105
+ const addr = ExcelUtils.stringifyRangeAddr({
106
+ s: { r: 0, c: 0 },
107
+ e: { r: 0, c: 0 },
108
+ });
109
+ expect(addr).toBe("A1");
110
+ });
111
+
112
+ it("converts multi-cell range to string", () => {
113
+ const addr = ExcelUtils.stringifyRangeAddr({
114
+ s: { r: 0, c: 0 },
115
+ e: { r: 2, c: 2 },
116
+ });
117
+ expect(addr).toBe("A1:C3");
118
+ });
119
+ });
120
+
121
+ describe("convertTimeTickToNumber / convertNumberToTimeTick", () => {
122
+ it("correctly converts 1970-01-01", () => {
123
+ const date = new Date(Date.UTC(1970, 0, 1, 0, 0, 0));
124
+ const tick = date.getTime();
125
+ const excelNum = ExcelUtils.convertTimeTickToNumber(tick);
126
+ // 1970-01-01 is 25569 days in Excel's date system
127
+ expect(excelNum).toBeCloseTo(25569, 0);
128
+ });
129
+
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
+ it("round-trip: tick → number → tick returns original value", () => {
150
+ const originalDate = new Date(Date.UTC(2024, 5, 15, 14, 30, 45));
151
+ const tick = originalDate.getTime();
152
+ const excelNum = ExcelUtils.convertTimeTickToNumber(tick);
153
+ const recoveredTick = ExcelUtils.convertNumberToTimeTick(excelNum);
154
+ // May not match exactly to milliseconds, so compare at second level
155
+ expect(Math.floor(recoveredTick / 1000)).toBe(Math.floor(tick / 1000));
156
+ });
157
+ });
158
+
159
+ describe("convertNumFmtCodeToName", () => {
160
+ it("recognizes General as number", () => {
161
+ expect(ExcelUtils.convertNumFmtCodeToName("General")).toBe("number");
162
+ });
163
+
164
+ it("recognizes date pattern as DateOnly", () => {
165
+ expect(ExcelUtils.convertNumFmtCodeToName("yyyy-mm-dd")).toBe("DateOnly");
166
+ expect(ExcelUtils.convertNumFmtCodeToName("yy/mm/dd")).toBe("DateOnly");
167
+ expect(ExcelUtils.convertNumFmtCodeToName("dd-mmm-yyyy")).toBe("DateOnly");
168
+ });
169
+
170
+ // NOTE: In the current implementation, 'mm' is used in both date (month) and time (minute)
171
+ // Regex: hasDate = /yy|dd|mm/i, hasTime = /hh|ss/i
172
+ // Therefore "hh:mm:ss" has hasDate(mm)=true, hasTime(hh,ss)=true → DateTime
173
+ // "h:mm" has hasDate(mm)=true, hasTime=false (h≠hh) → DateOnly
174
+ it("handles time pattern (note mm ambiguity)", () => {
175
+ // "hh:mm:ss": hasDate(mm)=true, hasTime(hh,ss)=true → DateTime
176
+ expect(ExcelUtils.convertNumFmtCodeToName("hh:mm:ss")).toBe("DateTime");
177
+ // "h:mm": hasDate(mm)=true, hasTime=false (h≠hh) → DateOnly
178
+ expect(ExcelUtils.convertNumFmtCodeToName("h:mm")).toBe("DateOnly");
179
+ // Pure time format (only ss, no mm)
180
+ expect(ExcelUtils.convertNumFmtCodeToName("[h]:ss")).toBe("Time");
181
+ });
182
+
183
+ it("recognizes date+time pattern as DateTime", () => {
184
+ expect(ExcelUtils.convertNumFmtCodeToName("yyyy-mm-dd hh:mm:ss")).toBe("DateTime");
185
+ // "yy/mm/dd h:mm" detects only date (h:mm has no hh and no ss)
186
+ expect(ExcelUtils.convertNumFmtCodeToName("yy/mm/dd h:mm")).toBe("DateOnly");
187
+ // Clear DateTime pattern
188
+ expect(ExcelUtils.convertNumFmtCodeToName("yyyy/mm/dd hh:mm:ss")).toBe("DateTime");
189
+ });
190
+
191
+ it("recognizes number pattern as number", () => {
192
+ expect(ExcelUtils.convertNumFmtCodeToName("#,##0")).toBe("number");
193
+ expect(ExcelUtils.convertNumFmtCodeToName("0.00")).toBe("number");
194
+ expect(ExcelUtils.convertNumFmtCodeToName("#,0")).toBe("number");
195
+ });
196
+
197
+ it("throws error on unknown format code input", () => {
198
+ expect(() => ExcelUtils.convertNumFmtCodeToName("unknown-format-xyz")).toThrow();
199
+ });
200
+ });
201
+
202
+ describe("convertNumFmtIdToName", () => {
203
+ it("recognizes common number formats", () => {
204
+ expect(ExcelUtils.convertNumFmtIdToName(0)).toBe("number");
205
+ expect(ExcelUtils.convertNumFmtIdToName(1)).toBe("number");
206
+ expect(ExcelUtils.convertNumFmtIdToName(2)).toBe("number");
207
+ });
208
+
209
+ it("recognizes date format", () => {
210
+ expect(ExcelUtils.convertNumFmtIdToName(14)).toBe("DateOnly");
211
+ expect(ExcelUtils.convertNumFmtIdToName(15)).toBe("DateOnly");
212
+ });
213
+
214
+ it("recognizes date+time format", () => {
215
+ expect(ExcelUtils.convertNumFmtIdToName(22)).toBe("DateTime");
216
+ });
217
+
218
+ it("recognizes time format", () => {
219
+ expect(ExcelUtils.convertNumFmtIdToName(18)).toBe("Time");
220
+ expect(ExcelUtils.convertNumFmtIdToName(19)).toBe("Time");
221
+ });
222
+
223
+ it("recognizes text format", () => {
224
+ expect(ExcelUtils.convertNumFmtIdToName(49)).toBe("string");
225
+ });
226
+
227
+ it("throws error on unknown numFmtId input", () => {
228
+ expect(() => ExcelUtils.convertNumFmtIdToName(23)).toThrow();
229
+ expect(() => ExcelUtils.convertNumFmtIdToName(100)).toThrow();
230
+ });
231
+ });
232
+
233
+ describe("convertNumFmtNameToId", () => {
234
+ it("converts format name to ID", () => {
235
+ expect(ExcelUtils.convertNumFmtNameToId("number")).toBe(0);
236
+ expect(ExcelUtils.convertNumFmtNameToId("DateOnly")).toBe(14);
237
+ expect(ExcelUtils.convertNumFmtNameToId("DateTime")).toBe(22);
238
+ expect(ExcelUtils.convertNumFmtNameToId("Time")).toBe(18);
239
+ expect(ExcelUtils.convertNumFmtNameToId("string")).toBe(49);
240
+ });
241
+ });
242
+ });