@simplysm/excel 1.0.138 → 13.0.0-beta.2

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 (207) hide show
  1. package/.cache/typecheck-browser.tsbuildinfo +1 -0
  2. package/.cache/typecheck-node.tsbuildinfo +1 -0
  3. package/.cache/typecheck-tests-browser.tsbuildinfo +1 -0
  4. package/.cache/typecheck-tests-node.tsbuildinfo +1 -0
  5. package/README.md +491 -0
  6. package/dist/core-common/src/common.types.d.ts +74 -0
  7. package/dist/core-common/src/common.types.d.ts.map +1 -0
  8. package/dist/core-common/src/env.d.ts +6 -0
  9. package/dist/core-common/src/env.d.ts.map +1 -0
  10. package/dist/core-common/src/errors/argument-error.d.ts +25 -0
  11. package/dist/core-common/src/errors/argument-error.d.ts.map +1 -0
  12. package/dist/core-common/src/errors/not-implemented-error.d.ts +29 -0
  13. package/dist/core-common/src/errors/not-implemented-error.d.ts.map +1 -0
  14. package/dist/core-common/src/errors/sd-error.d.ts +27 -0
  15. package/dist/core-common/src/errors/sd-error.d.ts.map +1 -0
  16. package/dist/core-common/src/errors/timeout-error.d.ts +31 -0
  17. package/dist/core-common/src/errors/timeout-error.d.ts.map +1 -0
  18. package/dist/core-common/src/extensions/arr-ext.d.ts +15 -0
  19. package/dist/core-common/src/extensions/arr-ext.d.ts.map +1 -0
  20. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts +19 -0
  21. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts.map +1 -0
  22. package/dist/core-common/src/extensions/arr-ext.types.d.ts +215 -0
  23. package/dist/core-common/src/extensions/arr-ext.types.d.ts.map +1 -0
  24. package/dist/core-common/src/extensions/map-ext.d.ts +57 -0
  25. package/dist/core-common/src/extensions/map-ext.d.ts.map +1 -0
  26. package/dist/core-common/src/extensions/set-ext.d.ts +36 -0
  27. package/dist/core-common/src/extensions/set-ext.d.ts.map +1 -0
  28. package/dist/core-common/src/features/debounce-queue.d.ts +53 -0
  29. package/dist/core-common/src/features/debounce-queue.d.ts.map +1 -0
  30. package/dist/core-common/src/features/event-emitter.d.ts +66 -0
  31. package/dist/core-common/src/features/event-emitter.d.ts.map +1 -0
  32. package/dist/core-common/src/features/serial-queue.d.ts +47 -0
  33. package/dist/core-common/src/features/serial-queue.d.ts.map +1 -0
  34. package/dist/core-common/src/index.d.ts +32 -0
  35. package/dist/core-common/src/index.d.ts.map +1 -0
  36. package/dist/core-common/src/types/date-only.d.ts +152 -0
  37. package/dist/core-common/src/types/date-only.d.ts.map +1 -0
  38. package/dist/core-common/src/types/date-time.d.ts +96 -0
  39. package/dist/core-common/src/types/date-time.d.ts.map +1 -0
  40. package/dist/core-common/src/types/lazy-gc-map.d.ts +80 -0
  41. package/dist/core-common/src/types/lazy-gc-map.d.ts.map +1 -0
  42. package/dist/core-common/src/types/time.d.ts +68 -0
  43. package/dist/core-common/src/types/time.d.ts.map +1 -0
  44. package/dist/core-common/src/types/uuid.d.ts +35 -0
  45. package/dist/core-common/src/types/uuid.d.ts.map +1 -0
  46. package/dist/core-common/src/utils/bytes.d.ts +51 -0
  47. package/dist/core-common/src/utils/bytes.d.ts.map +1 -0
  48. package/dist/core-common/src/utils/date-format.d.ts +90 -0
  49. package/dist/core-common/src/utils/date-format.d.ts.map +1 -0
  50. package/dist/core-common/src/utils/json.d.ts +34 -0
  51. package/dist/core-common/src/utils/json.d.ts.map +1 -0
  52. package/dist/core-common/src/utils/num.d.ts +60 -0
  53. package/dist/core-common/src/utils/num.d.ts.map +1 -0
  54. package/dist/core-common/src/utils/obj.d.ts +258 -0
  55. package/dist/core-common/src/utils/obj.d.ts.map +1 -0
  56. package/dist/core-common/src/utils/path.d.ts +23 -0
  57. package/dist/core-common/src/utils/path.d.ts.map +1 -0
  58. package/dist/core-common/src/utils/primitive.d.ts +18 -0
  59. package/dist/core-common/src/utils/primitive.d.ts.map +1 -0
  60. package/dist/core-common/src/utils/str.d.ts +103 -0
  61. package/dist/core-common/src/utils/str.d.ts.map +1 -0
  62. package/dist/core-common/src/utils/template-strings.d.ts +84 -0
  63. package/dist/core-common/src/utils/template-strings.d.ts.map +1 -0
  64. package/dist/core-common/src/utils/transferable.d.ts +47 -0
  65. package/dist/core-common/src/utils/transferable.d.ts.map +1 -0
  66. package/dist/core-common/src/utils/wait.d.ts +19 -0
  67. package/dist/core-common/src/utils/wait.d.ts.map +1 -0
  68. package/dist/core-common/src/utils/xml.d.ts +36 -0
  69. package/dist/core-common/src/utils/xml.d.ts.map +1 -0
  70. package/dist/core-common/src/zip/sd-zip.d.ts +80 -0
  71. package/dist/core-common/src/zip/sd-zip.d.ts.map +1 -0
  72. package/dist/excel/src/excel-cell.d.ts +68 -0
  73. package/dist/excel/src/excel-cell.d.ts.map +1 -0
  74. package/dist/excel/src/excel-col.d.ts +19 -0
  75. package/dist/excel/src/excel-col.d.ts.map +1 -0
  76. package/dist/excel/src/excel-row.d.ts +17 -0
  77. package/dist/excel/src/excel-row.d.ts.map +1 -0
  78. package/dist/excel/src/excel-workbook.d.ts +66 -0
  79. package/dist/excel/src/excel-workbook.d.ts.map +1 -0
  80. package/dist/excel/src/excel-worksheet.d.ts +102 -0
  81. package/dist/excel/src/excel-worksheet.d.ts.map +1 -0
  82. package/dist/excel/src/excel-wrapper.d.ts +42 -0
  83. package/dist/excel/src/excel-wrapper.d.ts.map +1 -0
  84. package/dist/excel/src/index.d.ts +9 -0
  85. package/dist/excel/src/index.d.ts.map +1 -0
  86. package/dist/excel/src/types.d.ts +445 -0
  87. package/dist/excel/src/types.d.ts.map +1 -0
  88. package/dist/excel/src/utils/excel-utils.d.ts +50 -0
  89. package/dist/excel/src/utils/excel-utils.d.ts.map +1 -0
  90. package/dist/excel/src/utils/zip-cache.d.ts +23 -0
  91. package/dist/excel/src/utils/zip-cache.d.ts.map +1 -0
  92. package/dist/excel/src/xml/excel-xml-content-type.d.ts +12 -0
  93. package/dist/excel/src/xml/excel-xml-content-type.d.ts.map +1 -0
  94. package/dist/excel/src/xml/excel-xml-drawing.d.ts +26 -0
  95. package/dist/excel/src/xml/excel-xml-drawing.d.ts.map +1 -0
  96. package/dist/excel/src/xml/excel-xml-relationship.d.ts +18 -0
  97. package/dist/excel/src/xml/excel-xml-relationship.d.ts.map +1 -0
  98. package/dist/excel/src/xml/excel-xml-shared-string.d.ts +19 -0
  99. package/dist/excel/src/xml/excel-xml-shared-string.d.ts.map +1 -0
  100. package/dist/excel/src/xml/excel-xml-style.d.ts +31 -0
  101. package/dist/excel/src/xml/excel-xml-style.d.ts.map +1 -0
  102. package/dist/excel/src/xml/excel-xml-unknown.d.ts +11 -0
  103. package/dist/excel/src/xml/excel-xml-unknown.d.ts.map +1 -0
  104. package/dist/excel/src/xml/excel-xml-workbook.d.ts +22 -0
  105. package/dist/excel/src/xml/excel-xml-workbook.d.ts.map +1 -0
  106. package/dist/excel/src/xml/excel-xml-worksheet.d.ts +103 -0
  107. package/dist/excel/src/xml/excel-xml-worksheet.d.ts.map +1 -0
  108. package/dist/excel-cell.js +261 -0
  109. package/dist/excel-cell.js.map +7 -0
  110. package/dist/excel-col.js +36 -0
  111. package/dist/excel-col.js.map +7 -0
  112. package/dist/excel-row.js +31 -0
  113. package/dist/excel-row.js.map +7 -0
  114. package/dist/excel-workbook.js +137 -0
  115. package/dist/excel-workbook.js.map +7 -0
  116. package/dist/excel-worksheet.js +279 -0
  117. package/dist/excel-worksheet.js.map +7 -0
  118. package/dist/excel-wrapper.js +220 -0
  119. package/dist/excel-wrapper.js.map +7 -0
  120. package/dist/index.js +9 -15
  121. package/dist/index.js.map +7 -1
  122. package/dist/types.js +1 -0
  123. package/dist/types.js.map +7 -0
  124. package/dist/utils/excel-utils.js +162 -0
  125. package/dist/utils/excel-utils.js.map +7 -0
  126. package/dist/utils/zip-cache.js +74 -0
  127. package/dist/utils/zip-cache.js.map +7 -0
  128. package/dist/xml/excel-xml-content-type.js +57 -0
  129. package/dist/xml/excel-xml-content-type.js.map +7 -0
  130. package/dist/xml/excel-xml-drawing.js +77 -0
  131. package/dist/xml/excel-xml-drawing.js.map +7 -0
  132. package/dist/xml/excel-xml-relationship.js +72 -0
  133. package/dist/xml/excel-xml-relationship.js.map +7 -0
  134. package/dist/xml/excel-xml-shared-string.js +61 -0
  135. package/dist/xml/excel-xml-shared-string.js.map +7 -0
  136. package/dist/xml/excel-xml-style.js +313 -0
  137. package/dist/xml/excel-xml-style.js.map +7 -0
  138. package/dist/xml/excel-xml-unknown.js +11 -0
  139. package/dist/xml/excel-xml-unknown.js.map +7 -0
  140. package/dist/xml/excel-xml-workbook.js +94 -0
  141. package/dist/xml/excel-xml-workbook.js.map +7 -0
  142. package/dist/xml/excel-xml-worksheet.js +405 -0
  143. package/dist/xml/excel-xml-worksheet.js.map +7 -0
  144. package/package.json +13 -7
  145. package/src/excel-cell.ts +326 -0
  146. package/src/excel-col.ts +43 -0
  147. package/src/excel-row.ts +37 -0
  148. package/src/excel-workbook.ts +206 -0
  149. package/src/excel-worksheet.ts +380 -0
  150. package/src/excel-wrapper.ts +219 -0
  151. package/src/index.ts +13 -9
  152. package/src/types.ts +396 -0
  153. package/src/utils/excel-utils.ts +201 -0
  154. package/src/utils/zip-cache.ts +103 -0
  155. package/src/xml/excel-xml-content-type.ts +64 -0
  156. package/src/xml/excel-xml-drawing.ts +87 -0
  157. package/src/xml/excel-xml-relationship.ts +86 -0
  158. package/src/xml/excel-xml-shared-string.ts +80 -0
  159. package/src/xml/excel-xml-style.ts +393 -0
  160. package/src/xml/excel-xml-unknown.ts +11 -0
  161. package/src/xml/excel-xml-workbook.ts +112 -0
  162. package/src/xml/excel-xml-worksheet.ts +544 -0
  163. package/tests/excel-cell.spec.ts +407 -0
  164. package/tests/excel-col.spec.ts +112 -0
  165. package/tests/excel-row.spec.ts +71 -0
  166. package/tests/excel-workbook.spec.ts +166 -0
  167. package/tests/excel-worksheet.spec.ts +389 -0
  168. package/tests/excel-wrapper.spec.ts +275 -0
  169. package/tests/fixtures/logo.png +0 -0
  170. package/tests/image-insert.spec.ts +188 -0
  171. package/tests/utils/excel-utils.spec.ts +240 -0
  172. package/dist/ExcelCell.d.ts +0 -13
  173. package/dist/ExcelCell.js +0 -161
  174. package/dist/ExcelCell.js.map +0 -1
  175. package/dist/ExcelCellStyle.d.ts +0 -31
  176. package/dist/ExcelCellStyle.js +0 -312
  177. package/dist/ExcelCellStyle.js.map +0 -1
  178. package/dist/ExcelColumn.d.ts +0 -8
  179. package/dist/ExcelColumn.js +0 -49
  180. package/dist/ExcelColumn.js.map +0 -1
  181. package/dist/ExcelRow.d.ts +0 -7
  182. package/dist/ExcelRow.js +0 -21
  183. package/dist/ExcelRow.js.map +0 -1
  184. package/dist/ExcelWorkbook.d.ts +0 -24
  185. package/dist/ExcelWorkbook.js +0 -418
  186. package/dist/ExcelWorkbook.js.map +0 -1
  187. package/dist/ExcelWorksheet.d.ts +0 -14
  188. package/dist/ExcelWorksheet.js +0 -31
  189. package/dist/ExcelWorksheet.js.map +0 -1
  190. package/dist/index.d.ts +0 -9
  191. package/dist/utils/ExcelUtils.d.ts +0 -14
  192. package/dist/utils/ExcelUtils.js +0 -66
  193. package/dist/utils/ExcelUtils.js.map +0 -1
  194. package/dist/utils/XmlConvert.d.ts +0 -4
  195. package/dist/utils/XmlConvert.js +0 -64
  196. package/dist/utils/XmlConvert.js.map +0 -1
  197. package/src/ExcelCell.ts +0 -163
  198. package/src/ExcelCellStyle.ts +0 -297
  199. package/src/ExcelColumn.ts +0 -46
  200. package/src/ExcelRow.ts +0 -17
  201. package/src/ExcelWorkbook.ts +0 -369
  202. package/src/ExcelWorksheet.ts +0 -27
  203. package/src/utils/ExcelUtils.ts +0 -68
  204. package/src/utils/XmlConvert.ts +0 -20
  205. package/tsconfig.build.json +0 -18
  206. package/tsconfig.json +0 -18
  207. package/tslint.json +0 -5
package/README.md ADDED
@@ -0,0 +1,491 @@
1
+ # @simplysm/excel
2
+
3
+ A TypeScript library for reading and writing Excel files (.xlsx). It works in both Node.js and browser environments, and internally uses a ZIP-based Lazy Loading structure for memory-efficient operation even with large files.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @simplysm/excel
9
+ # or
10
+ yarn add @simplysm/excel
11
+ # or
12
+ pnpm add @simplysm/excel
13
+ ```
14
+
15
+ ### Dependencies
16
+
17
+ | Package | Purpose |
18
+ |--------|------|
19
+ | `@simplysm/core-common` | Date/time types (`DateOnly`, `DateTime`, `Time`), utilities |
20
+ | `zod` | Schema-based data validation for `ExcelWrapper` |
21
+ | `mime` | MIME type determination for image insertion |
22
+
23
+ ## Core Modules
24
+
25
+ ### Core Classes
26
+
27
+ | Class | Description |
28
+ |--------|------|
29
+ | `ExcelWorkbook` | Workbook creation, opening, exporting, resource management |
30
+ | `ExcelWorksheet` | Worksheet access, data read/write, image insertion, view settings |
31
+ | `ExcelRow` | Row-level cell access |
32
+ | `ExcelCol` | Column-level cell access and width settings |
33
+ | `ExcelCell` | Cell value, formula, style, merge handling |
34
+
35
+ ### Wrapper Classes
36
+
37
+ | Class | Description |
38
+ |--------|------|
39
+ | `ExcelWrapper` | Type-safe Excel data conversion based on Zod schemas |
40
+
41
+ ### Utilities
42
+
43
+ | Class | Description |
44
+ |--------|------|
45
+ | `ExcelUtils` | Cell address conversion, date/number conversion, number format handling |
46
+
47
+ ### Types
48
+
49
+ | Type | Description |
50
+ |------|------|
51
+ | `ExcelValueType` | Cell value type (`number \| string \| DateOnly \| DateTime \| Time \| boolean \| undefined`) |
52
+ | `ExcelNumberFormat` | Number format (`"number" \| "string" \| "DateOnly" \| "DateTime" \| "Time"`) |
53
+ | `ExcelCellType` | Cell internal type (`"s" \| "b" \| "str" \| "n" \| "inlineStr" \| "e"`) |
54
+ | `ExcelStyleOptions` | Cell style options (background color, border, alignment, number format) |
55
+ | `ExcelBorderPosition` | Border position (`"left" \| "right" \| "top" \| "bottom"`) |
56
+ | `ExcelHorizontalAlign` | Horizontal alignment (`"center" \| "left" \| "right"`) |
57
+ | `ExcelVerticalAlign` | Vertical alignment (`"center" \| "top" \| "bottom"`) |
58
+ | `ExcelAddressPoint` | Cell coordinates (`{ r: number; c: number }`) |
59
+ | `ExcelAddressRangePoint` | Range coordinates (`{ s: ExcelAddressPoint; e: ExcelAddressPoint }`) |
60
+
61
+ ## Usage
62
+
63
+ ### Creating a New Workbook and Writing Cell Values
64
+
65
+ ```typescript
66
+ import { ExcelWorkbook } from "@simplysm/excel";
67
+
68
+ const wb = new ExcelWorkbook();
69
+ const ws = await wb.createWorksheet("Sheet1");
70
+
71
+ // Set cell values (both row and column are 0-based indices)
72
+ await ws.cell(0, 0).setVal("Name");
73
+ await ws.cell(0, 1).setVal("Age");
74
+ await ws.cell(1, 0).setVal("John Doe");
75
+ await ws.cell(1, 1).setVal(30);
76
+
77
+ // Export as Uint8Array
78
+ const bytes = await wb.getBytes();
79
+
80
+ // Or export as Blob (useful for browser downloads)
81
+ const blob = await wb.getBlob();
82
+
83
+ // Release resources (required)
84
+ await wb.close();
85
+ ```
86
+
87
+ ### Reading an Existing File
88
+
89
+ ```typescript
90
+ import { ExcelWorkbook } from "@simplysm/excel";
91
+
92
+ // Open workbook from Uint8Array or Blob
93
+ const wb = new ExcelWorkbook(bytes);
94
+
95
+ // Access worksheet by index (0-based)
96
+ const ws = await wb.getWorksheet(0);
97
+
98
+ // Or access worksheet by name
99
+ const wsByName = await wb.getWorksheet("Sheet1");
100
+
101
+ // Read cell values
102
+ const name = await ws.cell(0, 0).getVal(); // string | number | boolean | DateOnly | DateTime | Time | undefined
103
+ const age = await ws.cell(0, 1).getVal();
104
+
105
+ // Get list of worksheet names
106
+ const sheetNames = await wb.getWorksheetNames();
107
+
108
+ await wb.close();
109
+ ```
110
+
111
+ ### Resource Management (await using)
112
+
113
+ `ExcelWorkbook` implements `Symbol.asyncDispose` for automatic resource cleanup with the `await using` syntax.
114
+
115
+ ```typescript
116
+ import { ExcelWorkbook } from "@simplysm/excel";
117
+
118
+ // close() is automatically called when the scope ends
119
+ await using wb = new ExcelWorkbook(bytes);
120
+ const ws = await wb.getWorksheet(0);
121
+ const value = await ws.cell(0, 0).getVal();
122
+ ```
123
+
124
+ If you don't use `await using`, you must release resources with `try-finally`.
125
+
126
+ ```typescript
127
+ const wb = new ExcelWorkbook(bytes);
128
+ try {
129
+ const ws = await wb.getWorksheet(0);
130
+ // ... perform operations
131
+ } finally {
132
+ await wb.close();
133
+ }
134
+ ```
135
+
136
+ ### Setting Cell Styles
137
+
138
+ ```typescript
139
+ const cell = ws.cell(0, 0);
140
+
141
+ // Background color (ARGB 8-digit hexadecimal: AA=alpha, RR=red, GG=green, BB=blue)
142
+ await cell.setStyle({ background: "FFFF0000" }); // Red (opaque)
143
+ await cell.setStyle({ background: "00FFFF00" }); // Yellow
144
+
145
+ // Border
146
+ await cell.setStyle({ border: ["left", "right", "top", "bottom"] });
147
+
148
+ // Alignment
149
+ await cell.setStyle({
150
+ horizontalAlign: "center",
151
+ verticalAlign: "center",
152
+ });
153
+
154
+ // Number format
155
+ await cell.setStyle({ numberFormat: "number" });
156
+ await cell.setStyle({ numberFormat: "DateOnly" });
157
+ await cell.setStyle({ numberFormat: "DateTime" });
158
+ await cell.setStyle({ numberFormat: "Time" });
159
+ await cell.setStyle({ numberFormat: "string" });
160
+
161
+ // Apply multiple styles at once
162
+ await cell.setStyle({
163
+ background: "FFFF0000",
164
+ border: ["left", "right", "top", "bottom"],
165
+ horizontalAlign: "center",
166
+ verticalAlign: "center",
167
+ numberFormat: "number",
168
+ });
169
+ ```
170
+
171
+ ### Formulas
172
+
173
+ ```typescript
174
+ await ws.cell(0, 0).setVal(10);
175
+ await ws.cell(0, 1).setVal(20);
176
+ await ws.cell(0, 2).setFormula("A1+B1"); // Result: 30
177
+
178
+ // Read formula
179
+ const formula = await ws.cell(0, 2).getFormula(); // "A1+B1"
180
+
181
+ // Delete formula
182
+ await ws.cell(0, 2).setFormula(undefined);
183
+ ```
184
+
185
+ ### Cell Merging
186
+
187
+ ```typescript
188
+ await ws.cell(0, 0).setVal("Merged Cell");
189
+
190
+ // Merge from current cell (0,0) to (2,3) (3 rows x 4 columns area, i.e. A1:D3)
191
+ await ws.cell(0, 0).merge(2, 3);
192
+ ```
193
+
194
+ The arguments of the `merge(r, c)` method are the 0-based row/column indices of the merge endpoint.
195
+
196
+ ### Setting Column Width
197
+
198
+ ```typescript
199
+ // Set width of column 0 (column A) to 20
200
+ await ws.col(0).setWidth(20);
201
+ ```
202
+
203
+ ### Copying Rows/Cells
204
+
205
+ ```typescript
206
+ // Copy only the style of row 0 to row 2
207
+ await ws.copyRowStyle(0, 2);
208
+
209
+ // Copy entire row 0 to row 2 (values + styles)
210
+ await ws.copyRow(0, 2);
211
+
212
+ // Copy individual cell
213
+ await ws.copyCell({ r: 0, c: 0 }, { r: 1, c: 1 });
214
+
215
+ // Insert copy of source row at target position (existing rows shift down)
216
+ await ws.insertCopyRow(0, 3);
217
+ ```
218
+
219
+ ### Reading Data Table (getDataTable)
220
+
221
+ Converts worksheet data into a header-based record array. Uses the first row as headers and returns in `Record<string, ExcelValueType>[]` format.
222
+
223
+ ```typescript
224
+ // Basic usage: first row is header
225
+ const data = await ws.getDataTable();
226
+ // [{ "Name": "John Doe", "Age": 30 }, { "Name": "Jane Smith", "Age": 25 }]
227
+
228
+ // Specify header row index
229
+ const data2 = await ws.getDataTable({ headerRowIndex: 2 });
230
+
231
+ // Determine end of data when specific column is empty
232
+ const data3 = await ws.getDataTable({ checkEndColIndex: 0 });
233
+
234
+ // Filter to only use certain headers
235
+ const data4 = await ws.getDataTable({
236
+ usableHeaderNameFn: (name) => ["Name", "Age"].includes(name),
237
+ });
238
+ ```
239
+
240
+ ### Writing Data (setDataMatrix / setRecords)
241
+
242
+ ```typescript
243
+ // Write as 2D array
244
+ await ws.setDataMatrix([
245
+ ["Name", "Age"],
246
+ ["John Doe", 30],
247
+ ["Jane Smith", 25],
248
+ ]);
249
+
250
+ // Write as record array (automatic header generation)
251
+ await ws.setRecords([
252
+ { "Name": "John Doe", "Age": 30 },
253
+ { "Name": "Jane Smith", "Age": 25 },
254
+ ]);
255
+ ```
256
+
257
+ ### Inserting Images
258
+
259
+ ```typescript
260
+ await ws.addImage({
261
+ bytes: imageBytes, // Uint8Array
262
+ ext: "png", // Extension (png, jpg, etc.)
263
+ from: { r: 0, c: 0 }, // Start position (0-based)
264
+ to: { r: 5, c: 3 }, // End position (0-based)
265
+ });
266
+
267
+ // Specify offset in EMU (English Metric Units)
268
+ await ws.addImage({
269
+ bytes: imageBytes,
270
+ ext: "jpg",
271
+ from: { r: 0, c: 0, rOff: 0, cOff: 0 },
272
+ to: { r: 5, c: 3, rOff: 100000, cOff: 100000 },
273
+ });
274
+
275
+ // If 'to' is omitted, inserts at 'from' position with 1 cell size
276
+ await ws.addImage({
277
+ bytes: imageBytes,
278
+ ext: "png",
279
+ from: { r: 0, c: 0 },
280
+ });
281
+ ```
282
+
283
+ ### View Settings
284
+
285
+ ```typescript
286
+ // Set zoom level (percentage)
287
+ await ws.setZoom(85);
288
+
289
+ // Freeze rows/columns
290
+ await ws.setFix({ r: 0 }); // Freeze first row
291
+ await ws.setFix({ c: 0 }); // Freeze first column
292
+ await ws.setFix({ r: 0, c: 0 }); // Freeze first row + column
293
+ ```
294
+
295
+ ### Worksheet Name Management
296
+
297
+ ```typescript
298
+ const name = await ws.getName();
299
+ await ws.setName("New Sheet Name");
300
+ ```
301
+
302
+ ### ExcelWrapper (Zod Schema-based Wrapper)
303
+
304
+ `ExcelWrapper` is a wrapper class that allows type-safe reading and writing of Excel data based on Zod schemas.
305
+
306
+ ```typescript
307
+ import { z } from "zod";
308
+ import { ExcelWrapper } from "@simplysm/excel";
309
+
310
+ // 1. Define schema
311
+ const schema = z.object({
312
+ name: z.string(),
313
+ age: z.number(),
314
+ email: z.string().optional(),
315
+ active: z.boolean(),
316
+ });
317
+
318
+ // 2. Field name to display name mapping (names displayed in Excel headers)
319
+ const displayNameMap = {
320
+ name: "Name",
321
+ age: "Age",
322
+ email: "Email",
323
+ active: "Active Status",
324
+ };
325
+
326
+ const wrapper = new ExcelWrapper(schema, displayNameMap);
327
+ ```
328
+
329
+ #### Writing to Excel
330
+
331
+ ```typescript
332
+ const records = [
333
+ { name: "John Doe", age: 30, email: "john@test.com", active: true },
334
+ { name: "Jane Smith", age: 25, active: false },
335
+ ];
336
+
337
+ // write() returns ExcelWorkbook, so resource management is required
338
+ await using wb = await wrapper.write("Users", records);
339
+ const bytes = await wb.getBytes();
340
+ ```
341
+
342
+ The `write()` method automatically applies the following formatting:
343
+ - Borders on all cells
344
+ - Yellow background on required field headers (fields without optional/nullable/default)
345
+ - 85% zoom, freeze first row
346
+
347
+ #### Reading from Excel
348
+
349
+ ```typescript
350
+ // Read records from file (Uint8Array or Blob)
351
+ const records = await wrapper.read(bytes);
352
+ // records: { name: string; age: number; email?: string; active: boolean }[]
353
+
354
+ // Specify worksheet name or index
355
+ const records2 = await wrapper.read(bytes, "Users");
356
+ const records3 = await wrapper.read(bytes, 0);
357
+ ```
358
+
359
+ Behavior of the `read()` method:
360
+ - Only reads headers defined in the schema's `_displayNameMap`
361
+ - Skips rows where all values are empty
362
+ - Validates each row with the Zod schema, throws error on validation failure
363
+ - Throws error if there is no data
364
+ - Automatic type conversion: string -> number, string -> boolean ("1"/"true" -> true), etc.
365
+
366
+ ## ExcelUtils API
367
+
368
+ | Method | Input | Output | Description |
369
+ |--------|------|------|------|
370
+ | `stringifyAddr(point)` | `{ r: 0, c: 0 }` | `"A1"` | Convert coordinates to cell address string |
371
+ | `stringifyRowAddr(r)` | `0` | `"1"` | Convert row index to row address |
372
+ | `stringifyColAddr(c)` | `0` | `"A"` | Convert column index to column address (0~16383) |
373
+ | `parseCellAddrCode(addr)` | `"B3"` | `{ r: 2, c: 1 }` | Convert cell address to coordinates |
374
+ | `parseRowAddrCode(addr)` | `"A3"` | `2` | Extract row index from cell address |
375
+ | `parseColAddrCode(addr)` | `"B3"` | `1` | Extract column index from cell address |
376
+ | `parseRangeAddrCode(range)` | `"A1:C3"` | `{ s: {r:0,c:0}, e: {r:2,c:2} }` | Convert range address to coordinates |
377
+ | `stringifyRangeAddr(point)` | `{ s: {r:0,c:0}, e: {r:2,c:2} }` | `"A1:C3"` | Convert range coordinates to address string |
378
+ | `convertTimeTickToNumber(tick)` | JS timestamp (ms) | Excel date number | Convert JS date to Excel number |
379
+ | `convertNumberToTimeTick(num)` | Excel date number | JS timestamp (ms) | Convert Excel number to JS date |
380
+ | `convertNumFmtIdToName(id)` | Format ID | `ExcelNumberFormat` | Convert built-in format ID to name |
381
+ | `convertNumFmtCodeToName(code)` | Format code | `ExcelNumberFormat` | Convert format code to name |
382
+ | `convertNumFmtNameToId(name)` | `ExcelNumberFormat` | Format ID | Convert format name to ID |
383
+
384
+ ## ExcelCell API
385
+
386
+ | Method | Return Type | Description |
387
+ |--------|-----------|------|
388
+ | `getVal()` | `Promise<ExcelValueType>` | Get cell value |
389
+ | `setVal(val)` | `Promise<void>` | Set cell value (deletes cell if undefined) |
390
+ | `getFormula()` | `Promise<string \| undefined>` | Get formula |
391
+ | `setFormula(val)` | `Promise<void>` | Set formula (deletes formula if undefined) |
392
+ | `setStyle(opts)` | `Promise<void>` | Set style |
393
+ | `merge(r, c)` | `Promise<void>` | Merge from current cell to (r, c) |
394
+ | `getStyleId()` | `Promise<string \| undefined>` | Get style ID |
395
+ | `setStyleId(id)` | `Promise<void>` | Directly set style ID |
396
+
397
+ ## ExcelWorksheet API
398
+
399
+ | Method | Return Type | Description |
400
+ |--------|-----------|------|
401
+ | `cell(r, c)` | `ExcelCell` | Get cell object (0-based) |
402
+ | `row(r)` | `ExcelRow` | Get row object (0-based) |
403
+ | `col(c)` | `ExcelCol` | Get column object (0-based) |
404
+ | `getName()` | `Promise<string>` | Get worksheet name |
405
+ | `setName(name)` | `Promise<void>` | Change worksheet name |
406
+ | `getRange()` | `Promise<ExcelAddressRangePoint>` | Get data range |
407
+ | `getCells()` | `Promise<ExcelCell[][]>` | Get all cells as 2D array |
408
+ | `getDataTable(opt?)` | `Promise<Record<string, ExcelValueType>[]>` | Convert to header-based record array |
409
+ | `setDataMatrix(matrix)` | `Promise<void>` | Write 2D array data |
410
+ | `setRecords(records)` | `Promise<void>` | Write record array (automatic header generation) |
411
+ | `copyRow(src, target)` | `Promise<void>` | Copy row |
412
+ | `copyRowStyle(src, target)` | `Promise<void>` | Copy only row style |
413
+ | `copyCell(src, target)` | `Promise<void>` | Copy cell |
414
+ | `copyCellStyle(src, target)` | `Promise<void>` | Copy only cell style |
415
+ | `insertCopyRow(src, target)` | `Promise<void>` | Insert copy of row (existing rows shift) |
416
+ | `addImage(opts)` | `Promise<void>` | Insert image |
417
+ | `setZoom(percent)` | `Promise<void>` | Set zoom level |
418
+ | `setFix(point)` | `Promise<void>` | Set freeze panes |
419
+
420
+ ## ExcelWorkbook API
421
+
422
+ | Method | Return Type | Description |
423
+ |--------|-----------|------|
424
+ | `getWorksheet(nameOrIndex)` | `Promise<ExcelWorksheet>` | Get worksheet (name or 0-based index) |
425
+ | `createWorksheet(name)` | `Promise<ExcelWorksheet>` | Create new worksheet |
426
+ | `getWorksheetNames()` | `Promise<string[]>` | Get all worksheet names |
427
+ | `getBytes()` | `Promise<Bytes>` | Export as Uint8Array |
428
+ | `getBlob()` | `Promise<Blob>` | Export as Blob |
429
+ | `close()` | `Promise<void>` | Release resources |
430
+
431
+ ## Important Notes
432
+
433
+ ### All Cell Methods are Asynchronous
434
+
435
+ All cell-related methods in this library are designed as `async`. This is due to the Lazy Loading structure for memory efficiency with large files. Only the necessary XML is loaded selectively depending on the cell type:
436
+
437
+ - Reading string cells: Loads SharedStrings.xml
438
+ - Reading number cells: Does not load SharedStrings
439
+ - Cells with styles: Loads Styles.xml
440
+
441
+ ```typescript
442
+ // Correct usage
443
+ const value = await cell.getVal();
444
+ await cell.setVal("Hello");
445
+
446
+ // Incorrect usage - returns Promise object
447
+ const value = cell.getVal();
448
+ cell.setVal("Hello");
449
+ ```
450
+
451
+ ### Resource Cleanup is Required
452
+
453
+ `ExcelWorkbook` manages ZIP resources internally, so you must call `close()` after use or use `await using`. After calling `close()`, the workbook instance cannot be used.
454
+
455
+ ### Resource Management of ExcelWrapper.write()
456
+
457
+ `ExcelWrapper.write()` returns `ExcelWorkbook`, so the caller must manage the resource.
458
+
459
+ ```typescript
460
+ // Correct usage
461
+ await using wb = await wrapper.write("Sheet1", records);
462
+ const bytes = await wb.getBytes();
463
+
464
+ // Or
465
+ const wb = await wrapper.write("Sheet1", records);
466
+ try {
467
+ const bytes = await wb.getBytes();
468
+ } finally {
469
+ await wb.close();
470
+ }
471
+ ```
472
+
473
+ ### Background Color Format
474
+
475
+ Background colors use the ARGB 8-digit hexadecimal format. It must satisfy the `/^[0-9A-F]{8}$/i` pattern, otherwise an error will occur.
476
+
477
+ ```
478
+ Format: AARRGGBB
479
+ AA = alpha (00=transparent, FF=opaque, but reversed in Excel: 00=opaque)
480
+ RR = red
481
+ GG = green
482
+ BB = blue
483
+ ```
484
+
485
+ ### 0-based Indexing
486
+
487
+ All row/column indices are 0-based. Cell A1 in Excel corresponds to `cell(0, 0)`, cell B3 corresponds to `cell(2, 1)`.
488
+
489
+ ## License
490
+
491
+ Apache-2.0
@@ -0,0 +1,74 @@
1
+ import { DateTime } from "./types/date-time";
2
+ import { DateOnly } from "./types/date-only";
3
+ import { Time } from "./types/time";
4
+ import { Uuid } from "./types/uuid";
5
+ /**
6
+ * Buffer 대신 사용하는 바이너리 타입
7
+ */
8
+ export type Bytes = Uint8Array;
9
+ /**
10
+ * Primitive 타입 매핑
11
+ * orm-common과 공유
12
+ */
13
+ export type PrimitiveTypeMap = {
14
+ string: string;
15
+ number: number;
16
+ boolean: boolean;
17
+ DateTime: DateTime;
18
+ DateOnly: DateOnly;
19
+ Time: Time;
20
+ Uuid: Uuid;
21
+ Bytes: Bytes;
22
+ };
23
+ /**
24
+ * Primitive 타입 문자열 키
25
+ */
26
+ export type PrimitiveTypeStr = keyof PrimitiveTypeMap;
27
+ /**
28
+ * Primitive 타입 유니온
29
+ */
30
+ export type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined;
31
+ /**
32
+ * 깊은 Partial 타입
33
+ *
34
+ * 객체의 모든 속성을 재귀적으로 선택적(optional)으로 만듭니다.
35
+ * Primitive 타입(string, number, boolean 등)은 그대로 유지하고,
36
+ * 객체/배열 타입만 재귀적으로 Partial을 적용합니다.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * interface User {
41
+ * name: string;
42
+ * profile: {
43
+ * age: number;
44
+ * address: { city: string };
45
+ * };
46
+ * }
47
+ *
48
+ * // 모든 깊이의 속성이 선택적이 됨
49
+ * const partial: DeepPartial<User> = {
50
+ * profile: { address: {} }
51
+ * };
52
+ * ```
53
+ */
54
+ export type DeepPartial<T> = Partial<{
55
+ [K in keyof T]: T[K] extends PrimitiveType ? T[K] : DeepPartial<T[K]>;
56
+ }>;
57
+ /**
58
+ * 생성자 타입
59
+ *
60
+ * 클래스 생성자를 타입으로 표현할 때 사용합니다.
61
+ * 주로 의존성 주입, 팩토리 패턴, instanceof 체크 등에서 활용됩니다.
62
+ *
63
+ * @example
64
+ * function create<T>(ctor: Type<T>): T {
65
+ * return new ctor();
66
+ * }
67
+ *
68
+ * class MyClass { name = "test"; }
69
+ * const instance = create(MyClass); // MyClass 인스턴스
70
+ */
71
+ export interface Type<T> extends Function {
72
+ new (...args: unknown[]): T;
73
+ }
74
+ //# sourceMappingURL=common.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.types.d.ts","sourceRoot":"","sources":["../../../../core-common/src/common.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAIpC;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC;AAM/B;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,gBAAgB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,SAAS,CAAC;AAM3E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC;KAClC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtE,CAAC,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,IAAI,CAAC,CAAC,CAAE,SAAQ,QAAQ;IACvC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;CAC7B"}
@@ -0,0 +1,6 @@
1
+ export declare const env: {
2
+ DEV: boolean;
3
+ VER?: string;
4
+ [key: string]: unknown;
5
+ };
6
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../core-common/src/env.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,GAAG,EAAE;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAKxB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { SdError } from "./sd-error";
2
+ /**
3
+ * 인수 오류
4
+ *
5
+ * 잘못된 인수를 받았을 때 발생시키는 에러이다.
6
+ * 인수 객체를 YAML 형식으로 메시지에 포함하여 디버깅을 용이하게 한다.
7
+ *
8
+ * @example
9
+ * // 인수 객체만 전달
10
+ * throw new ArgumentError({ userId: 123, name: null });
11
+ * // 결과 메시지: "인수가 잘못되었습니다.\n\nuserId: 123\nname: null"
12
+ *
13
+ * @example
14
+ * // 커스텀 메시지와 인수 객체 전달
15
+ * throw new ArgumentError("유효하지 않은 사용자", { userId: 123 });
16
+ * // 결과 메시지: "유효하지 않은 사용자\n\nuserId: 123"
17
+ */
18
+ export declare class ArgumentError extends SdError {
19
+ /** 기본 메시지("인수가 잘못되었습니다.")와 함께 인수 객체를 YAML 형식으로 출력 */
20
+ constructor(argObj: Record<string, unknown>);
21
+ /** 커스텀 메시지와 함께 인수 객체를 YAML 형식으로 출력 */
22
+ constructor(message: string, argObj: Record<string, unknown>);
23
+ constructor(arg1: Record<string, unknown> | string, arg2?: Record<string, unknown>);
24
+ }
25
+ //# sourceMappingURL=argument-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argument-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/argument-error.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,SAAQ,OAAO;IACxC,qDAAqD;gBACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3C,sCAAsC;gBAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAChD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAYnF"}
@@ -0,0 +1,29 @@
1
+ import { SdError } from "./sd-error";
2
+ /**
3
+ * 미구현 오류
4
+ *
5
+ * 아직 구현되지 않은 기능을 호출했을 때 발생시키는 에러이다.
6
+ * 추상 메서드 스텁, 향후 구현 예정인 분기 등에 사용한다.
7
+ *
8
+ * @example
9
+ * // 추상 메서드 구현 전
10
+ * class BaseService {
11
+ * process(): void {
12
+ * throw new NotImplementedError("서브클래스에서 구현 필요");
13
+ * }
14
+ * }
15
+ *
16
+ * @example
17
+ * // 향후 구현 예정 분기
18
+ * switch (type) {
19
+ * case "A": return handleA();
20
+ * case "B": throw new NotImplementedError(`타입 ${type} 처리`);
21
+ * }
22
+ */
23
+ export declare class NotImplementedError extends SdError {
24
+ /**
25
+ * @param message 추가 설명 메시지
26
+ */
27
+ constructor(message?: string);
28
+ }
29
+ //# sourceMappingURL=not-implemented-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-implemented-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/not-implemented-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,mBAAoB,SAAQ,OAAO;IAC9C;;OAEG;gBACS,OAAO,CAAC,EAAE,MAAM;CAI7B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 오류의 Tree 구조 구성이 가능한 오류 클래스
3
+ * ES2024 cause 속성 활용
4
+ *
5
+ * @example
6
+ * // 원인 에러를 감싸서 생성
7
+ * try {
8
+ * await fetch(url);
9
+ * } catch (err) {
10
+ * throw new SdError(err, "API 호출 실패", "사용자 로드 실패");
11
+ * }
12
+ * // 결과 메시지: "사용자 로드 실패 => API 호출 실패 => 원본 에러 메시지"
13
+ *
14
+ * @example
15
+ * // 메시지만으로 생성
16
+ * throw new SdError("잘못된 상태", "처리 불가");
17
+ * // 결과 메시지: "처리 불가 => 잘못된 상태"
18
+ */
19
+ export declare class SdError extends Error {
20
+ cause?: Error;
21
+ /** 원인 에러를 감싸서 생성. 메시지는 역순으로 연결됨 (상위 메시지 => 하위 메시지 => 원인 메시지) */
22
+ constructor(cause: Error, ...messages: string[]);
23
+ /** 메시지만으로 생성. 메시지는 역순으로 연결됨 (상위 메시지 => 하위 메시지) */
24
+ constructor(...messages: string[]);
25
+ constructor(arg1?: unknown, ...messages: string[]);
26
+ }
27
+ //# sourceMappingURL=sd-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sd-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/sd-error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,OAAQ,SAAQ,KAAK;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IAEvB,gEAAgE;gBACpD,KAAK,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE;IAC/C,kDAAkD;gBACtC,GAAG,QAAQ,EAAE,MAAM,EAAE;gBACrB,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE;CA2BlD"}