@simplysm/excel 14.0.100 → 14.0.102

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 (184) hide show
  1. package/dist/biff/biff-model-factory.d.ts +32 -0
  2. package/dist/biff/biff-model-factory.d.ts.map +1 -0
  3. package/dist/biff/biff-model-factory.js +88 -0
  4. package/dist/biff/biff-model-factory.js.map +1 -0
  5. package/dist/biff/biff-ptg.d.ts +14 -0
  6. package/dist/biff/biff-ptg.d.ts.map +1 -0
  7. package/dist/biff/biff-ptg.js +277 -0
  8. package/dist/biff/biff-ptg.js.map +1 -0
  9. package/dist/biff/biff-records.d.ts +163 -0
  10. package/dist/biff/biff-records.d.ts.map +1 -0
  11. package/dist/biff/biff-records.js +579 -0
  12. package/dist/biff/biff-records.js.map +1 -0
  13. package/dist/biff/biff-shared-string-model.d.ts +13 -0
  14. package/dist/biff/biff-shared-string-model.d.ts.map +1 -0
  15. package/dist/biff/biff-shared-string-model.js +41 -0
  16. package/dist/biff/biff-shared-string-model.js.map +1 -0
  17. package/dist/biff/biff-style-model.d.ts +39 -0
  18. package/dist/biff/biff-style-model.d.ts.map +1 -0
  19. package/dist/biff/biff-style-model.js +182 -0
  20. package/dist/biff/biff-style-model.js.map +1 -0
  21. package/dist/biff/biff-workbook-model.d.ts +17 -0
  22. package/dist/biff/biff-workbook-model.d.ts.map +1 -0
  23. package/dist/biff/biff-workbook-model.js +64 -0
  24. package/dist/biff/biff-workbook-model.js.map +1 -0
  25. package/dist/biff/biff-worksheet-model.d.ts +69 -0
  26. package/dist/biff/biff-worksheet-model.d.ts.map +1 -0
  27. package/dist/biff/biff-worksheet-model.js +495 -0
  28. package/dist/biff/biff-worksheet-model.js.map +1 -0
  29. package/dist/biff/biff12-codec.d.ts +149 -0
  30. package/dist/biff/biff12-codec.d.ts.map +1 -0
  31. package/dist/biff/biff12-codec.js +262 -0
  32. package/dist/biff/biff12-codec.js.map +1 -0
  33. package/dist/excel-cell.d.ts +0 -6
  34. package/dist/excel-cell.d.ts.map +1 -1
  35. package/dist/excel-cell.js +2 -24
  36. package/dist/excel-cell.js.map +1 -1
  37. package/dist/excel-col.js.map +1 -1
  38. package/dist/excel-row.js.map +1 -1
  39. package/dist/excel-workbook.d.ts +4 -21
  40. package/dist/excel-workbook.d.ts.map +1 -1
  41. package/dist/excel-workbook.js +16 -49
  42. package/dist/excel-workbook.js.map +1 -1
  43. package/dist/excel-worksheet.d.ts +0 -11
  44. package/dist/excel-worksheet.d.ts.map +1 -1
  45. package/dist/excel-worksheet.js +9 -46
  46. package/dist/excel-worksheet.js.map +1 -1
  47. package/dist/excel-wrapper.d.ts +0 -10
  48. package/dist/excel-wrapper.d.ts.map +1 -1
  49. package/dist/excel-wrapper.js +0 -10
  50. package/dist/excel-wrapper.js.map +1 -1
  51. package/dist/models/excel-format.d.ts +3 -0
  52. package/dist/models/excel-format.d.ts.map +1 -0
  53. package/dist/models/excel-format.js +2 -0
  54. package/dist/models/excel-format.js.map +1 -0
  55. package/dist/models/excel-model-factory.d.ts +33 -0
  56. package/dist/models/excel-model-factory.d.ts.map +1 -0
  57. package/dist/models/excel-model-factory.js +2 -0
  58. package/dist/models/excel-model-factory.js.map +1 -0
  59. package/dist/models/excel-model.d.ts +12 -0
  60. package/dist/models/excel-model.d.ts.map +1 -0
  61. package/dist/models/excel-model.js +2 -0
  62. package/dist/models/excel-model.js.map +1 -0
  63. package/dist/models/i-content-type-model.d.ts +7 -0
  64. package/dist/models/i-content-type-model.d.ts.map +1 -0
  65. package/dist/models/i-content-type-model.js +2 -0
  66. package/dist/models/i-content-type-model.js.map +1 -0
  67. package/dist/models/i-drawing-model.d.ts +23 -0
  68. package/dist/models/i-drawing-model.d.ts.map +1 -0
  69. package/dist/models/i-drawing-model.js +2 -0
  70. package/dist/models/i-drawing-model.js.map +1 -0
  71. package/dist/models/i-relationship-model.d.ts +16 -0
  72. package/dist/models/i-relationship-model.d.ts.map +1 -0
  73. package/dist/models/i-relationship-model.js +2 -0
  74. package/dist/models/i-relationship-model.js.map +1 -0
  75. package/dist/models/i-shared-string-model.d.ts +9 -0
  76. package/dist/models/i-shared-string-model.d.ts.map +1 -0
  77. package/dist/models/i-shared-string-model.js +2 -0
  78. package/dist/models/i-shared-string-model.js.map +1 -0
  79. package/dist/models/i-style-model.d.ts +18 -0
  80. package/dist/models/i-style-model.d.ts.map +1 -0
  81. package/dist/models/i-style-model.js +2 -0
  82. package/dist/models/i-style-model.js.map +1 -0
  83. package/dist/models/i-workbook-model.d.ts +17 -0
  84. package/dist/models/i-workbook-model.d.ts.map +1 -0
  85. package/dist/models/i-workbook-model.js +2 -0
  86. package/dist/models/i-workbook-model.js.map +1 -0
  87. package/dist/models/i-worksheet-model.d.ts +39 -0
  88. package/dist/models/i-worksheet-model.d.ts.map +1 -0
  89. package/dist/models/i-worksheet-model.js +2 -0
  90. package/dist/models/i-worksheet-model.js.map +1 -0
  91. package/dist/models/shared/excel-cf-spec.d.ts +13 -0
  92. package/dist/models/shared/excel-cf-spec.d.ts.map +1 -0
  93. package/dist/models/shared/excel-cf-spec.js +2 -0
  94. package/dist/models/shared/excel-cf-spec.js.map +1 -0
  95. package/dist/models/shared/excel-style.d.ts +24 -0
  96. package/dist/models/shared/excel-style.d.ts.map +1 -0
  97. package/dist/models/shared/excel-style.js +38 -0
  98. package/dist/models/shared/excel-style.js.map +1 -0
  99. package/dist/types.d.ts +0 -13
  100. package/dist/types.d.ts.map +1 -1
  101. package/dist/types.js.map +1 -1
  102. package/dist/utils/excel-style-data.d.ts +3 -5
  103. package/dist/utils/excel-style-data.d.ts.map +1 -1
  104. package/dist/utils/excel-style-data.js +2 -16
  105. package/dist/utils/excel-style-data.js.map +1 -1
  106. package/dist/utils/zip-cache.d.ts +46 -9
  107. package/dist/utils/zip-cache.d.ts.map +1 -1
  108. package/dist/utils/zip-cache.js +138 -52
  109. package/dist/utils/zip-cache.js.map +1 -1
  110. package/dist/xml/excel-xml-content-type.d.ts +8 -4
  111. package/dist/xml/excel-xml-content-type.d.ts.map +1 -1
  112. package/dist/xml/excel-xml-content-type.js +13 -6
  113. package/dist/xml/excel-xml-content-type.js.map +1 -1
  114. package/dist/xml/excel-xml-drawing.d.ts +8 -4
  115. package/dist/xml/excel-xml-drawing.d.ts.map +1 -1
  116. package/dist/xml/excel-xml-drawing.js +14 -7
  117. package/dist/xml/excel-xml-drawing.js.map +1 -1
  118. package/dist/xml/excel-xml-relationship.d.ts +12 -4
  119. package/dist/xml/excel-xml-relationship.d.ts.map +1 -1
  120. package/dist/xml/excel-xml-relationship.js +22 -12
  121. package/dist/xml/excel-xml-relationship.js.map +1 -1
  122. package/dist/xml/excel-xml-shared-string.d.ts +8 -4
  123. package/dist/xml/excel-xml-shared-string.d.ts.map +1 -1
  124. package/dist/xml/excel-xml-shared-string.js +16 -9
  125. package/dist/xml/excel-xml-shared-string.js.map +1 -1
  126. package/dist/xml/excel-xml-style.d.ts +11 -22
  127. package/dist/xml/excel-xml-style.d.ts.map +1 -1
  128. package/dist/xml/excel-xml-style.js +66 -92
  129. package/dist/xml/excel-xml-style.js.map +1 -1
  130. package/dist/xml/excel-xml-unknown.d.ts +6 -5
  131. package/dist/xml/excel-xml-unknown.d.ts.map +1 -1
  132. package/dist/xml/excel-xml-unknown.js +7 -4
  133. package/dist/xml/excel-xml-unknown.js.map +1 -1
  134. package/dist/xml/excel-xml-workbook.d.ts +9 -4
  135. package/dist/xml/excel-xml-workbook.d.ts.map +1 -1
  136. package/dist/xml/excel-xml-workbook.js +28 -20
  137. package/dist/xml/excel-xml-workbook.js.map +1 -1
  138. package/dist/xml/excel-xml-worksheet.d.ts +12 -7
  139. package/dist/xml/excel-xml-worksheet.d.ts.map +1 -1
  140. package/dist/xml/excel-xml-worksheet.js +65 -50
  141. package/dist/xml/excel-xml-worksheet.js.map +1 -1
  142. package/dist/xml/xml-model-factory.d.ts +25 -0
  143. package/dist/xml/xml-model-factory.d.ts.map +1 -0
  144. package/dist/xml/xml-model-factory.js +66 -0
  145. package/dist/xml/xml-model-factory.js.map +1 -0
  146. package/package.json +2 -2
  147. package/src/biff/biff-model-factory.ts +101 -0
  148. package/src/biff/biff-ptg.ts +289 -0
  149. package/src/biff/biff-records.ts +686 -0
  150. package/src/biff/biff-shared-string-model.ts +52 -0
  151. package/src/biff/biff-style-model.ts +219 -0
  152. package/src/biff/biff-workbook-model.ts +83 -0
  153. package/src/biff/biff-worksheet-model.ts +545 -0
  154. package/src/biff/biff12-codec.ts +286 -0
  155. package/src/excel-cell.ts +12 -46
  156. package/src/excel-col.ts +3 -3
  157. package/src/excel-row.ts +3 -3
  158. package/src/excel-workbook.ts +26 -69
  159. package/src/excel-worksheet.ts +36 -107
  160. package/src/excel-wrapper.ts +0 -10
  161. package/src/models/excel-format.ts +2 -0
  162. package/src/models/excel-model-factory.ts +33 -0
  163. package/src/models/excel-model.ts +12 -0
  164. package/src/models/i-content-type-model.ts +7 -0
  165. package/src/models/i-drawing-model.ts +13 -0
  166. package/src/models/i-relationship-model.ts +13 -0
  167. package/src/models/i-shared-string-model.ts +9 -0
  168. package/src/models/i-style-model.ts +18 -0
  169. package/src/models/i-workbook-model.ts +17 -0
  170. package/src/models/i-worksheet-model.ts +40 -0
  171. package/src/models/shared/excel-cf-spec.ts +24 -0
  172. package/src/models/shared/excel-style.ts +65 -0
  173. package/src/types.ts +0 -13
  174. package/src/utils/excel-style-data.ts +4 -25
  175. package/src/utils/zip-cache.ts +189 -58
  176. package/src/xml/excel-xml-content-type.ts +18 -8
  177. package/src/xml/excel-xml-drawing.ts +19 -9
  178. package/src/xml/excel-xml-relationship.ts +28 -14
  179. package/src/xml/excel-xml-shared-string.ts +20 -11
  180. package/src/xml/excel-xml-style.ts +74 -116
  181. package/src/xml/excel-xml-unknown.ts +8 -4
  182. package/src/xml/excel-xml-workbook.ts +34 -22
  183. package/src/xml/excel-xml-worksheet.ts +73 -53
  184. package/src/xml/xml-model-factory.ts +83 -0
@@ -0,0 +1,286 @@
1
+ /**
2
+ * BIFF12 (MS-XLSB) record 프레이밍 + 프리미티브 코덱.
3
+ *
4
+ * adtek `biff12.ts` 에서 포팅한 재사용 기반(varint record 프레이밍·LE r/w·XLWideString·cell prefix·RK decode).
5
+ * 레코드 종류별 encode/decode 는 `biff-records.ts`, 모델 단위 직렬화는 `biff-*-model.ts` 가 담당한다.
6
+ *
7
+ * record 형식:
8
+ * - type ID: 1~2 byte varint (high bit = continuation)
9
+ * - length: 1~4 byte varint
10
+ * - payload: length byte
11
+ *
12
+ * 브라우저/Node 양쪽 동작을 위해 `Buffer` 를 쓰지 않고 `Uint8Array`/`DataView` 만 사용한다.
13
+ */
14
+
15
+ /** BIFF12 record type ID 상수. ([MS-XLSB] record 번호) */
16
+ export const REC = {
17
+ BrtRowHdr: 0x0000,
18
+ BrtCellRk: 0x0002,
19
+ BrtCellReal: 0x0005,
20
+ BrtCellSt: 0x0006,
21
+ BrtCellIsst: 0x0007,
22
+ BrtBeginSheetData: 0x0091,
23
+ BrtEndSheetData: 0x0092,
24
+ BrtCellBlank: 0x0001,
25
+ BrtCellBool: 0x0004,
26
+ BrtWsDim: 0x0094,
27
+ BrtSSTItem: 0x0013,
28
+ BrtBundleSh: 0x009c,
29
+ /** BrtColInfo (0x003c): 컬럼 메타 (colFirst/colLast/coldx/ixfe). 컬럼 기본 셀 서식. */
30
+ BrtColInfo: 0x003c,
31
+ /**
32
+ * "Short" cell variants — sheet-js 가 iStyleRef=0 인 cell 에 사용.
33
+ * prefix 가 8 byte (col+iStyleRef+phShow) 대신 4 byte (col 만).
34
+ */
35
+ BrtShortBlank: 0x000c,
36
+ BrtShortRk: 0x000d,
37
+ BrtShortReal: 0x0010,
38
+ BrtShortSt: 0x0011,
39
+ BrtShortIsst: 0x0012,
40
+ // 컨테이너 begin/end — boa-sample.xlsb 정답지로 확정한 record ID.
41
+ BrtBeginBook: 0x0083,
42
+ BrtEndBook: 0x0084,
43
+ BrtBeginBundleShs: 0x008f,
44
+ BrtEndBundleShs: 0x0090,
45
+ BrtBeginSst: 0x009f,
46
+ BrtEndSst: 0x00a0,
47
+ BrtBeginSheet: 0x0081,
48
+ BrtEndSheet: 0x0082,
49
+ // 병합/뷰/컬럼/autoFilter
50
+ BrtMergeCell: 0x00b0,
51
+ BrtBeginMergeCells: 0x00b1,
52
+ BrtEndMergeCells: 0x00b2,
53
+ BrtBeginAFilter: 0x00a1,
54
+ BrtEndAFilter: 0x00a2,
55
+ BrtBeginColInfos: 0x0186,
56
+ BrtEndColInfos: 0x0187,
57
+ BrtPane: 0x0097,
58
+ BrtBeginWsView: 0x0089,
59
+ BrtEndWsView: 0x008a,
60
+ BrtBeginWsViews: 0x0085,
61
+ BrtEndWsViews: 0x0086,
62
+ BrtSel: 0x0098,
63
+ BrtBeginBookViews: 0x0087,
64
+ BrtEndBookViews: 0x0088,
65
+ BrtBookView: 0x009e,
66
+ BrtWbProp: 0x0099,
67
+ BrtFileVersion: 0x0080,
68
+ BrtSheetFormatPr: 0x01e5,
69
+ BrtWsProp: 0x0093,
70
+ // 스타일(styles.bin)
71
+ BrtFmt: 0x002c,
72
+ BrtXF: 0x002f,
73
+ BrtBeginCellXFs: 0x0269,
74
+ BrtEndCellXFs: 0x026a,
75
+ BrtBeginStyleSheet: 0x0116,
76
+ BrtEndStyleSheet: 0x0117,
77
+ BrtBeginFmts: 0x0267,
78
+ BrtEndFmts: 0x0268,
79
+ BrtFont: 0x002b,
80
+ BrtBeginFonts: 0x0263,
81
+ BrtEndFonts: 0x0264,
82
+ BrtFill: 0x002d,
83
+ BrtBeginFills: 0x025b,
84
+ BrtEndFills: 0x025c,
85
+ BrtBorder: 0x002e,
86
+ BrtBeginBorders: 0x0265,
87
+ BrtEndBorders: 0x0266,
88
+ BrtBeginCellStyleXFs: 0x0272,
89
+ BrtEndCellStyleXFs: 0x0273,
90
+ // 이미지(drawing)
91
+ BrtDrawing: 0x0226,
92
+ // 조건부 서식
93
+ BrtBeginConditionalFormatting: 0x01cd,
94
+ BrtEndConditionalFormatting: 0x01ce,
95
+ BrtBeginCFRule: 0x01cf,
96
+ BrtEndCFRule: 0x01d0,
97
+ BrtBeginDXFs: 0x01f9,
98
+ BrtEndDXFs: 0x01fa,
99
+ BrtDXF: 0x01fb,
100
+ // 수식 셀
101
+ BrtFmlaString: 0x0008,
102
+ BrtFmlaNum: 0x0009,
103
+ BrtFmlaBool: 0x000a,
104
+ BrtFmlaError: 0x000b,
105
+ } as const;
106
+
107
+ /** Excel serial(1900 base) ↔ Unix epoch 일수 오프셋. */
108
+ export const EXCEL_EPOCH_OFFSET = 25569;
109
+
110
+ export interface IRecord {
111
+ type: number;
112
+ payload: Uint8Array;
113
+ /** 원본 buffer 안 record header 시작 offset (insert point 계산용) */
114
+ offset: number;
115
+ /** record 전체 크기(header + payload) */
116
+ totalLength: number;
117
+ }
118
+
119
+ /** buffer 의 모든 record 를 순회. */
120
+ export function readAllRecords(buf: Uint8Array): IRecord[] {
121
+ const out: IRecord[] = [];
122
+ let pos = 0;
123
+ while (pos < buf.length) {
124
+ const start = pos;
125
+ let type: number;
126
+ if ((buf[pos] & 0x80) === 0) {
127
+ type = buf[pos];
128
+ pos += 1;
129
+ } else {
130
+ type = (buf[pos] & 0x7f) | (buf[pos + 1] << 7);
131
+ pos += 2;
132
+ }
133
+ let length = 0;
134
+ let shift = 0;
135
+ for (let i = 0; i < 4; i++) {
136
+ const b = buf[pos];
137
+ pos += 1;
138
+ length |= (b & 0x7f) << shift;
139
+ if ((b & 0x80) === 0) break;
140
+ shift += 7;
141
+ }
142
+ const payload = buf.subarray(pos, pos + length);
143
+ pos += length;
144
+ out.push({ type, payload, offset: start, totalLength: pos - start });
145
+ }
146
+ return out;
147
+ }
148
+
149
+ /** record header(type+length) 를 byte 배열로 직렬화. */
150
+ export function encodeRecordHeader(type: number, length: number): Uint8Array {
151
+ const bytes: number[] = [];
152
+ if (type < 0x80) {
153
+ bytes.push(type);
154
+ } else {
155
+ bytes.push((type & 0x7f) | 0x80);
156
+ bytes.push((type >> 7) & 0xff);
157
+ }
158
+ let remain = length;
159
+ do {
160
+ let b = remain & 0x7f;
161
+ remain >>>= 7;
162
+ if (remain > 0) b |= 0x80;
163
+ bytes.push(b);
164
+ } while (remain > 0);
165
+ return new Uint8Array(bytes);
166
+ }
167
+
168
+ /** record (header + payload) 직렬화. */
169
+ export function encodeRecord(type: number, payload: Uint8Array): Uint8Array {
170
+ const header = encodeRecordHeader(type, payload.length);
171
+ const out = new Uint8Array(header.length + payload.length);
172
+ out.set(header, 0);
173
+ out.set(payload, header.length);
174
+ return out;
175
+ }
176
+
177
+ /** 여러 Uint8Array 를 하나로 concat. */
178
+ export function concatBytes(arrs: Uint8Array[]): Uint8Array {
179
+ let total = 0;
180
+ for (const a of arrs) total += a.length;
181
+ const out = new Uint8Array(total);
182
+ let off = 0;
183
+ for (const a of arrs) {
184
+ out.set(a, off);
185
+ off += a.length;
186
+ }
187
+ return out;
188
+ }
189
+
190
+ /** UInt32LE write. */
191
+ export function writeUint32LE(buf: Uint8Array, off: number, v: number): void {
192
+ buf[off] = v & 0xff;
193
+ buf[off + 1] = (v >>> 8) & 0xff;
194
+ buf[off + 2] = (v >>> 16) & 0xff;
195
+ buf[off + 3] = (v >>> 24) & 0xff;
196
+ }
197
+
198
+ /** UInt32LE read. */
199
+ export function readUint32LE(buf: Uint8Array, off: number): number {
200
+ return (
201
+ (buf[off] | (buf[off + 1] << 8) | (buf[off + 2] << 16) | (buf[off + 3] << 24)) >>> 0
202
+ );
203
+ }
204
+
205
+ /**
206
+ * BIFF12 cell record 의 prefix 8 byte (col + iStyleRef + flag) 읽기.
207
+ *
208
+ * Layout:
209
+ * - 4 byte: col index (UInt32LE)
210
+ * - 3 byte: iStyleRef (24-bit LE)
211
+ * - 1 byte: cellPhShow (보통 0)
212
+ */
213
+ export function readCellPrefix(payload: Uint8Array): { col: number; iStyleRef: number } {
214
+ const col = readUint32LE(payload, 0);
215
+ const iStyleRef = payload[4] | (payload[5] << 8) | (payload[6] << 16);
216
+ return { col, iStyleRef };
217
+ }
218
+
219
+ /** cell prefix 8 byte 작성. */
220
+ export function writeCellPrefix(
221
+ buf: Uint8Array,
222
+ off: number,
223
+ col: number,
224
+ iStyleRef: number,
225
+ ): void {
226
+ writeUint32LE(buf, off, col);
227
+ buf[off + 4] = iStyleRef & 0xff;
228
+ buf[off + 5] = (iStyleRef >>> 8) & 0xff;
229
+ buf[off + 6] = (iStyleRef >>> 16) & 0xff;
230
+ buf[off + 7] = 0; // cellPhShow
231
+ }
232
+
233
+ /** XLWideString 작성 (UInt32 length + UTF-16LE chars). */
234
+ export function encodeXLWideString(s: string): Uint8Array {
235
+ const out = new Uint8Array(4 + s.length * 2);
236
+ writeUint32LE(out, 0, s.length);
237
+ for (let i = 0; i < s.length; i++) {
238
+ const code = s.charCodeAt(i);
239
+ out[4 + i * 2] = code & 0xff;
240
+ out[4 + i * 2 + 1] = (code >>> 8) & 0xff;
241
+ }
242
+ return out;
243
+ }
244
+
245
+ /**
246
+ * XLWideString read — UInt32 length + UTF-16LE chars.
247
+ * @returns value 와 소비한 byte 수 (4 + length*2).
248
+ */
249
+ export function readXLWideString(
250
+ payload: Uint8Array,
251
+ offset: number,
252
+ ): { value: string; bytesRead: number } {
253
+ const length = readUint32LE(payload, offset);
254
+ let s = "";
255
+ for (let i = 0; i < length; i++) {
256
+ const lo = payload[offset + 4 + i * 2];
257
+ const hi = payload[offset + 4 + i * 2 + 1];
258
+ s += String.fromCharCode(lo | (hi << 8));
259
+ }
260
+ return { value: s, bytesRead: 4 + length * 2 };
261
+ }
262
+
263
+ /** BrtCellRk 의 RK number decode. */
264
+ export function decodeRkNumber(rk: number): number {
265
+ const fX100 = (rk & 0x1) !== 0;
266
+ const fInt = (rk & 0x2) !== 0;
267
+ let value: number;
268
+ if (fInt) {
269
+ let v = rk >> 2;
270
+ if ((v & 0x20000000) !== 0) v -= 0x40000000;
271
+ value = v;
272
+ } else {
273
+ const buf = new ArrayBuffer(8);
274
+ const view = new DataView(buf);
275
+ view.setUint32(4, rk & 0xfffffffc, true);
276
+ view.setUint32(0, 0, true);
277
+ value = view.getFloat64(0, true);
278
+ }
279
+ if (fX100) value /= 100;
280
+ return value;
281
+ }
282
+
283
+ /** Excel serial number(1900 base, UTC) → JS Date. */
284
+ export function excelSerialToDate(serial: number): Date {
285
+ return new Date(Math.round((serial - EXCEL_EPOCH_OFFSET) * 86400000));
286
+ }
package/src/excel-cell.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { ExcelXmlWorksheet } from "./xml/excel-xml-worksheet";
2
- import type { ExcelXmlContentType } from "./xml/excel-xml-content-type";
3
- import type { ExcelXmlRelationship } from "./xml/excel-xml-relationship";
4
- import type { ExcelXmlStyle, ExcelStyle } from "./xml/excel-xml-style";
5
- import type { ExcelXmlSharedString } from "./xml/excel-xml-shared-string";
1
+ import type { IWorksheetModel } from "./models/i-worksheet-model";
2
+ import type { IStyleModel } from "./models/i-style-model";
3
+ import type { ISharedStringModel } from "./models/i-shared-string-model";
4
+ import type { ExcelStyle } from "./models/shared/excel-style";
5
+ import { convertExcelStyleOptions } from "./models/shared/excel-style";
6
6
  import type { ZipCache } from "./utils/zip-cache";
7
7
  import type { ExcelAddressPoint, ExcelStyleOptions, ExcelValueType } from "./types";
8
8
  import {
@@ -12,8 +12,6 @@ import {
12
12
  str,
13
13
  Time,
14
14
  } from "@simplysm/core-common";
15
- import { ExcelXmlSharedString as ExcelXmlSharedStringClass } from "./xml/excel-xml-shared-string";
16
- import { convertExcelStyleOptions } from "./xml/excel-xml-style";
17
15
  import { ExcelUtils } from "./utils/excel-utils";
18
16
  import { getOrCreateStyleData } from "./utils/excel-style-data";
19
17
 
@@ -200,9 +198,6 @@ export class ExcelCell {
200
198
  * 현재 셀에서 지정된 끝 좌표까지 셀 병합
201
199
  * @param r 병합 끝 행 인덱스 (0 기반)
202
200
  * @param c 병합 끝 열 인덱스 (0 기반)
203
- * @example
204
- * // A1 셀에서 호출하여 A1:C3 범위 병합 (3행 x 3열)
205
- * await ws.cell(0, 0).merge(2, 2);
206
201
  */
207
202
  async merge(r: number, c: number): Promise<void> {
208
203
  const wsData = await this._getWsData();
@@ -249,8 +244,8 @@ export class ExcelCell {
249
244
  wsData.deleteCell(addr);
250
245
  }
251
246
 
252
- private async _getWsData(): Promise<ExcelXmlWorksheet> {
253
- return (await this._zipCache.get(`xl/worksheets/${this._targetFileName}`)) as ExcelXmlWorksheet;
247
+ private async _getWsData(): Promise<IWorksheetModel> {
248
+ return (await this._zipCache.get(`xl/worksheets/${this._targetFileName}`)) as IWorksheetModel;
254
249
  }
255
250
 
256
251
  private async _setStyleInternal(style: ExcelStyle): Promise<void> {
@@ -265,44 +260,15 @@ export class ExcelCell {
265
260
  wsData.setCellStyleId(this.addr, styleId);
266
261
  }
267
262
 
268
- private async _getTypeData(): Promise<ExcelXmlContentType> {
269
- return (await this._zipCache.get("[Content_Types].xml")) as ExcelXmlContentType;
263
+ private async _getStyleData(): Promise<IStyleModel | undefined> {
264
+ return (await this._zipCache.get("xl/styles.xml")) as IStyleModel | undefined;
270
265
  }
271
266
 
272
- private async _getSsData(): Promise<ExcelXmlSharedString | undefined> {
273
- return (await this._zipCache.get("xl/sharedStrings.xml")) as ExcelXmlSharedString | undefined;
267
+ private async _getOrCreateSsData(): Promise<ISharedStringModel> {
268
+ return this._zipCache.ensureSharedStrings();
274
269
  }
275
270
 
276
- private async _getWbRelData(): Promise<ExcelXmlRelationship> {
277
- return (await this._zipCache.get("xl/_rels/workbook.xml.rels")) as ExcelXmlRelationship;
278
- }
279
-
280
- private async _getStyleData(): Promise<ExcelXmlStyle | undefined> {
281
- return (await this._zipCache.get("xl/styles.xml")) as ExcelXmlStyle | undefined;
282
- }
283
-
284
- private async _getOrCreateSsData(): Promise<ExcelXmlSharedString> {
285
- let ssData = await this._getSsData();
286
- if (ssData == null) {
287
- ssData = new ExcelXmlSharedStringClass();
288
- this._zipCache.set("xl/sharedStrings.xml", ssData);
289
-
290
- const typeData = await this._getTypeData();
291
- typeData.add(
292
- "/xl/sharedStrings.xml",
293
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
294
- );
295
-
296
- const wbRelData = await this._getWbRelData();
297
- wbRelData.add(
298
- "sharedStrings.xml",
299
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
300
- );
301
- }
302
- return ssData;
303
- }
304
-
305
- private async _getOrCreateStyleData(): Promise<ExcelXmlStyle> {
271
+ private async _getOrCreateStyleData(): Promise<IStyleModel> {
306
272
  return getOrCreateStyleData(this._zipCache);
307
273
  }
308
274
 
package/src/excel-col.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ExcelCell } from "./excel-cell";
2
- import type { ExcelXmlWorksheet } from "./xml/excel-xml-worksheet";
2
+ import type { IWorksheetModel } from "./models/i-worksheet-model";
3
3
  import type { ZipCache } from "./utils/zip-cache";
4
4
 
5
5
  /** Excel 워크시트의 열을 나타내는 클래스. 셀 접근 및 열 너비 설정 기능을 제공한다. */
@@ -35,7 +35,7 @@ export class ExcelCol {
35
35
  wsData.setColWidth((this._c + 1).toString(), size.toString());
36
36
  }
37
37
 
38
- private async _getWsData(): Promise<ExcelXmlWorksheet> {
39
- return (await this._zipCache.get(`xl/worksheets/${this._targetFileName}`)) as ExcelXmlWorksheet;
38
+ private async _getWsData(): Promise<IWorksheetModel> {
39
+ return (await this._zipCache.get(`xl/worksheets/${this._targetFileName}`)) as IWorksheetModel;
40
40
  }
41
41
  }
package/src/excel-row.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ExcelCell } from "./excel-cell";
2
- import type { ExcelXmlWorksheet } from "./xml/excel-xml-worksheet";
2
+ import type { IWorksheetModel } from "./models/i-worksheet-model";
3
3
  import type { ZipCache } from "./utils/zip-cache";
4
4
 
5
5
  /** Excel 워크시트의 행을 나타내는 클래스. 셀 접근 기능을 제공한다. */
@@ -29,7 +29,7 @@ export class ExcelRow {
29
29
  return result;
30
30
  }
31
31
 
32
- private async _getWsData(): Promise<ExcelXmlWorksheet> {
33
- return (await this._zipCache.get(`xl/worksheets/${this._targetFileName}`)) as ExcelXmlWorksheet;
32
+ private async _getWsData(): Promise<IWorksheetModel> {
33
+ return (await this._zipCache.get(`xl/worksheets/${this._targetFileName}`)) as IWorksheetModel;
34
34
  }
35
35
  }
@@ -1,12 +1,10 @@
1
1
  import type { Bytes } from "@simplysm/core-common";
2
2
  import { ExcelWorksheet } from "./excel-worksheet";
3
+ import type { IRelationshipModel } from "./models/i-relationship-model";
4
+ import type { IWorkbookModel } from "./models/i-workbook-model";
5
+ import type { ExcelFormat } from "./models/excel-format";
6
+ import { convertExcelStyleOptions } from "./models/shared/excel-style";
3
7
  import { ZipCache } from "./utils/zip-cache";
4
- import { ExcelXmlContentType } from "./xml/excel-xml-content-type";
5
- import { ExcelXmlRelationship } from "./xml/excel-xml-relationship";
6
- import type { ExcelXmlWorkbook } from "./xml/excel-xml-workbook";
7
- import { ExcelXmlWorkbook as ExcelXmlWorkbookClass } from "./xml/excel-xml-workbook";
8
- import { ExcelXmlWorksheet as ExcelXmlWorksheetClass } from "./xml/excel-xml-worksheet";
9
- import { convertExcelStyleOptions } from "./xml/excel-xml-style";
10
8
  import { getOrCreateStyleData } from "./utils/excel-style-data";
11
9
  import type { ExcelStyleOptions } from "./types";
12
10
 
@@ -23,17 +21,6 @@ import type { ExcelStyleOptions } from "./types";
23
21
  * - ZIP 내부의 XML은 접근 시점에만 읽고 파싱함
24
22
  * - SharedStrings, Styles 등 대용량 XML은 필요할 때만 로드함
25
23
  * - 극단적인 경우에도 메모리 효율적 (예: 1TB SharedStrings가 있는 파일에서 숫자 셀 하나만 읽기)
26
- *
27
- * @example
28
- * ```typescript
29
- * const wb = new ExcelWorkbook(bytes);
30
- * try {
31
- * const ws = await wb.getWorksheet(0);
32
- * // ... 작업 수행
33
- * } finally {
34
- * await wb.close();
35
- * }
36
- * ```
37
24
  */
38
25
  export class ExcelWorkbook {
39
26
  readonly zipCache: ZipCache;
@@ -43,32 +30,29 @@ export class ExcelWorkbook {
43
30
  /**
44
31
  * @param arg 기존 Excel 파일 데이터 (Blob 또는 Uint8Array). 생략하면 새 워크북을 생성한다.
45
32
  */
46
- constructor(arg?: Blob | Bytes) {
47
- if (arg != null) {
33
+ constructor(arg?: Blob | Bytes | { format?: ExcelFormat }) {
34
+ if (arg instanceof Blob || ArrayBuffer.isView(arg)) {
48
35
  this.zipCache = new ZipCache(arg);
49
36
  } else {
50
- this.zipCache = new ZipCache();
37
+ const format = arg?.format ?? "xlsx";
38
+ this.zipCache = new ZipCache(undefined, format);
51
39
 
52
- // 전역 ContentTypes
53
- const typeXml = new ExcelXmlContentType();
54
- this.zipCache.set("[Content_Types].xml", typeXml);
40
+ // 전역 ContentTypes (포맷별 골격)
41
+ this.zipCache.set("[Content_Types].xml", this.zipCache.createContentType());
55
42
 
56
- // 전역 Rels
43
+ // 전역 Rels (xlsb 는 workbook.bin 을 가리킨다)
44
+ const wbPartName = format === "xlsb" ? "xl/workbook.bin" : "xl/workbook.xml";
57
45
  this.zipCache.set(
58
46
  "_rels/.rels",
59
- new ExcelXmlRelationship().add(
60
- "xl/workbook.xml",
47
+ this.zipCache.createRelationship().add(
48
+ wbPartName,
61
49
  "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
62
50
  ),
63
51
  );
64
52
 
65
- // 워크북
66
- const wbXml = new ExcelXmlWorkbookClass();
67
- this.zipCache.set("xl/workbook.xml", wbXml);
68
-
69
- // 워크북 Rels
70
- const wbRelXml = new ExcelXmlRelationship();
71
- this.zipCache.set("xl/_rels/workbook.xml.rels", wbRelXml);
53
+ // 워크북 + 워크북 Rels
54
+ this.zipCache.set("xl/workbook.xml", this.zipCache.createWorkbook());
55
+ this.zipCache.set("xl/_rels/workbook.xml.rels", this.zipCache.createRelationship());
72
56
  }
73
57
  }
74
58
 
@@ -83,39 +67,21 @@ export class ExcelWorkbook {
83
67
  /** 워크북의 모든 워크시트 이름 반환 */
84
68
  async getWorksheetNames(): Promise<string[]> {
85
69
  this._ensureNotClosed();
86
- const wbData = (await this.zipCache.get("xl/workbook.xml")) as ExcelXmlWorkbook;
70
+ const wbData = (await this.zipCache.get("xl/workbook.xml")) as IWorkbookModel;
87
71
  return wbData.sheetNames;
88
72
  }
89
73
 
90
74
  /** 새 워크시트를 생성하여 반환 */
91
75
  async addWorksheet(name: string): Promise<ExcelWorksheet> {
92
76
  this._ensureNotClosed();
93
- // 워크북
94
- const wbXml = (await this.zipCache.get("xl/workbook.xml")) as ExcelXmlWorkbook;
77
+ // 워크북에 시트 엔트리 추가
78
+ const wbXml = (await this.zipCache.get("xl/workbook.xml")) as IWorkbookModel;
95
79
  const newWsRelId = wbXml.addWorksheet(name).lastWsRelId!;
96
80
 
97
- // Content Types 갱신
98
- const typeXml = (await this.zipCache.get("[Content_Types].xml")) as ExcelXmlContentType;
99
- typeXml.add(
100
- `/xl/worksheets/sheet${newWsRelId}.xml`,
101
- "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
102
- );
103
-
104
- // 워크북 Rels 갱신
105
- const wbRelXml = (await this.zipCache.get(
106
- "xl/_rels/workbook.xml.rels",
107
- )) as ExcelXmlRelationship;
108
- wbRelXml.insert(
109
- newWsRelId,
110
- `worksheets/sheet${newWsRelId}.xml`,
111
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
112
- );
113
-
114
- // 워크시트
115
- const wsXml = new ExcelXmlWorksheetClass();
116
- this.zipCache.set(`xl/worksheets/sheet${newWsRelId}.xml`, wsXml);
117
-
118
- const ws = new ExcelWorksheet(this.zipCache, newWsRelId, `sheet${newWsRelId}.xml`);
81
+ // content-type·rels·빈 worksheet 파트 등록 (포맷별 처리는 ZipCache 위임)
82
+ const fileName = await this.zipCache.registerWorksheet(newWsRelId);
83
+
84
+ const ws = new ExcelWorksheet(this.zipCache, newWsRelId, fileName);
119
85
  this._wsMap.set(newWsRelId, ws);
120
86
  return ws;
121
87
  }
@@ -123,7 +89,7 @@ export class ExcelWorkbook {
123
89
  /** 이름 또는 인덱스(0 기반)로 워크시트 조회 */
124
90
  async getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet> {
125
91
  this._ensureNotClosed();
126
- const wbData = (await this.zipCache.get("xl/workbook.xml")) as ExcelXmlWorkbook;
92
+ const wbData = (await this.zipCache.get("xl/workbook.xml")) as IWorkbookModel;
127
93
  const wsId =
128
94
  typeof nameOrIndex === "string"
129
95
  ? wbData.getWsRelIdByName(nameOrIndex)
@@ -141,7 +107,7 @@ export class ExcelWorkbook {
141
107
  return this._wsMap.get(wsId)!;
142
108
  }
143
109
 
144
- const relData = (await this.zipCache.get("xl/_rels/workbook.xml.rels")) as ExcelXmlRelationship;
110
+ const relData = (await this.zipCache.get("xl/_rels/workbook.xml.rels")) as IRelationshipModel;
145
111
  const targetFilePath = relData.getTargetByRelId(wsId);
146
112
  if (targetFilePath == null) {
147
113
  throw new Error(`시트 관계 정보를 찾을 수 없습니다: rId${wsId}`);
@@ -173,15 +139,6 @@ export class ExcelWorkbook {
173
139
  *
174
140
  * 옵션이 없는 자원은 0번 슬롯이 빈 슬롯 (`{}` / patternType="none") 으로 reset 된다.
175
141
  * 미호출 시 `cellXfs[0]` 과 0번 슬롯 모두 원본이 그대로 보존된다.
176
- *
177
- * @example
178
- * ```typescript
179
- * const wb = new ExcelWorkbook();
180
- * await wb.setDefaultStyle({
181
- * font: { family: "맑은 고딕", size: 10 },
182
- * horizontalAlign: "center",
183
- * });
184
- * ```
185
142
  */
186
143
  async setDefaultStyle(opts: ExcelStyleOptions): Promise<void> {
187
144
  this._ensureNotClosed();