@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
@@ -1,14 +1,16 @@
1
+ import type { Bytes } from "@simplysm/core-common";
1
2
  import type {
2
3
  ExcelAddressRangePoint,
3
4
  ExcelCellData,
4
5
  ExcelCellType,
5
6
  ExcelRowData,
6
- ExcelXml,
7
7
  ExcelXmlCfRuleData,
8
8
  ExcelXmlWorksheetData,
9
9
  } from "../types";
10
+ import type { ICfRuleSpec } from "../models/shared/excel-cf-spec";
11
+ import type { IWorksheetModel } from "../models/i-worksheet-model";
10
12
  import { ExcelUtils } from "../utils/excel-utils";
11
- import { num, obj } from "@simplysm/core-common";
13
+ import { num, obj, xml as xmlU } from "@simplysm/core-common";
12
14
  import "@simplysm/core-common";
13
15
 
14
16
  interface RowInfo {
@@ -20,14 +22,14 @@ interface RowInfo {
20
22
  * xl/worksheets/sheet*.xml 파일을 관리하는 클래스.
21
23
  * 셀 데이터, 병합, 열 너비, 행 높이 등을 처리한다.
22
24
  */
23
- export class ExcelXmlWorksheet implements ExcelXml {
24
- data: ExcelXmlWorksheetData;
25
+ export class ExcelXmlWorksheet implements IWorksheetModel {
26
+ private readonly _data: ExcelXmlWorksheetData;
25
27
 
26
28
  private readonly _dataMap: Map<number, RowInfo>;
27
29
 
28
30
  constructor(data?: ExcelXmlWorksheetData) {
29
31
  if (data == null) {
30
- this.data = {
32
+ this._data = {
31
33
  worksheet: {
32
34
  $: {
33
35
  xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -43,10 +45,10 @@ export class ExcelXmlWorksheet implements ExcelXml {
43
45
  },
44
46
  };
45
47
  } else {
46
- this.data = data;
48
+ this._data = data;
47
49
  }
48
50
 
49
- this._dataMap = (this.data.worksheet.sheetData[0].row ?? []).toMap(
51
+ this._dataMap = (this._data.worksheet.sheetData[0].row ?? []).toMap(
50
52
  (row) => ExcelUtils.parseRowAddr(row.$.r),
51
53
  (row) => ({
52
54
  data: row,
@@ -58,6 +60,11 @@ export class ExcelXmlWorksheet implements ExcelXml {
58
60
  );
59
61
  }
60
62
 
63
+ /** @internal 테스트·디버그용 내부 트리 접근. 상위 레이어는 인터페이스만 사용. */
64
+ get data(): ExcelXmlWorksheetData {
65
+ return this._data;
66
+ }
67
+
61
68
  get range(): ExcelAddressRangePoint {
62
69
  let maxRow = 0;
63
70
  let maxCol = 0;
@@ -153,7 +160,7 @@ export class ExcelXmlWorksheet implements ExcelXml {
153
160
  }
154
161
 
155
162
  setMergeCells(startAddr: { r: number; c: number }, endAddr: { r: number; c: number }): void {
156
- const mergeCells = (this.data.worksheet.mergeCells = this.data.worksheet.mergeCells ?? [
163
+ const mergeCells = (this._data.worksheet.mergeCells = this._data.worksheet.mergeCells ?? [
157
164
  {
158
165
  $: { count: "0" },
159
166
  mergeCell: [],
@@ -194,17 +201,17 @@ export class ExcelXmlWorksheet implements ExcelXml {
194
201
  }
195
202
 
196
203
  getMergeCells(): { s: { r: number; c: number }; e: { r: number; c: number } }[] {
197
- const mergeCells = this.data.worksheet.mergeCells;
204
+ const mergeCells = this._data.worksheet.mergeCells;
198
205
  if (mergeCells == null) return [];
199
206
  return mergeCells[0].mergeCell.map((item) => ExcelUtils.parseRangeAddr(item.$.ref));
200
207
  }
201
208
 
202
209
  removeMergeCells(fromAddr: { r: number; c: number }, toAddr: { r: number; c: number }): void {
203
- if (this.data.worksheet.mergeCells == null) return;
210
+ if (this._data.worksheet.mergeCells == null) return;
204
211
 
205
212
  const range = { s: fromAddr, e: toAddr };
206
213
 
207
- const filteredMergeCells = this.data.worksheet.mergeCells[0].mergeCell.filter((item) => {
214
+ const filteredMergeCells = this._data.worksheet.mergeCells[0].mergeCell.filter((item) => {
208
215
  const rangeAddr = ExcelUtils.parseRangeAddr(item.$.ref);
209
216
  return !(
210
217
  rangeAddr.s.r >= range.s.r &&
@@ -215,10 +222,10 @@ export class ExcelXmlWorksheet implements ExcelXml {
215
222
  });
216
223
 
217
224
  if (filteredMergeCells.length === 0) {
218
- delete this.data.worksheet.mergeCells;
225
+ delete this._data.worksheet.mergeCells;
219
226
  } else {
220
- this.data.worksheet.mergeCells[0].mergeCell = filteredMergeCells;
221
- this.data.worksheet.mergeCells[0].$.count = filteredMergeCells.length.toString();
227
+ this._data.worksheet.mergeCells[0].mergeCell = filteredMergeCells;
228
+ this._data.worksheet.mergeCells[0].$.count = filteredMergeCells.length.toString();
222
229
  }
223
230
  }
224
231
 
@@ -226,9 +233,9 @@ export class ExcelXmlWorksheet implements ExcelXml {
226
233
  * `<conditionalFormatting>` 블록을 시트에 push.
227
234
  * priority 는 시트 전역 카운터(기존 cfRule 의 최대 priority + 1)부터 호출 내 rules 순서대로 부여.
228
235
  */
229
- addConditionalFormatting(sqref: string, rules: { dxfId: string; cfRule: Omit<ExcelXmlCfRuleData["$"], "priority" | "dxfId"> & { formula: string[] } }[]): void {
230
- const cfList = (this.data.worksheet.conditionalFormatting =
231
- this.data.worksheet.conditionalFormatting ?? []);
236
+ addConditionalFormatting(sqref: string, rules: { dxfId: string; cfRule: ICfRuleSpec }[]): void {
237
+ const cfList = (this._data.worksheet.conditionalFormatting =
238
+ this._data.worksheet.conditionalFormatting ?? []);
232
239
 
233
240
  let nextPriority = 1;
234
241
  for (const block of cfList) {
@@ -258,7 +265,7 @@ export class ExcelXmlWorksheet implements ExcelXml {
258
265
  }
259
266
 
260
267
  shiftMergeCells(fromRow: number, delta: number): void {
261
- const mergeCells = this.data.worksheet.mergeCells;
268
+ const mergeCells = this._data.worksheet.mergeCells;
262
269
  if (mergeCells == null) return;
263
270
 
264
271
  for (const mergeCell of mergeCells[0].mergeCell) {
@@ -290,7 +297,7 @@ export class ExcelXmlWorksheet implements ExcelXml {
290
297
  throw new Error(`잘못된 열 인덱스: ${colIndex}`);
291
298
  }
292
299
 
293
- const cols = this.data.worksheet.cols?.[0];
300
+ const cols = this._data.worksheet.cols?.[0];
294
301
 
295
302
  // 대상 열을 포함하는 기존 범위 찾기
296
303
  const col = cols
@@ -357,8 +364,8 @@ export class ExcelXmlWorksheet implements ExcelXml {
357
364
  }
358
365
  } else {
359
366
  // 기존 범위 없음: 새 범위 생성
360
- this.data.worksheet.cols = this.data.worksheet.cols ?? [{ col: [] }];
361
- this.data.worksheet.cols[0].col.push({
367
+ this._data.worksheet.cols = this._data.worksheet.cols ?? [{ col: [] }];
368
+ this._data.worksheet.cols[0].col.push({
362
369
  $: {
363
370
  min: colIndex,
364
371
  max: colIndex,
@@ -371,24 +378,24 @@ export class ExcelXmlWorksheet implements ExcelXml {
371
378
  }
372
379
 
373
380
  setTabColor(rgb: string): void {
374
- this.data.worksheet.sheetPr = this.data.worksheet.sheetPr ?? [{}];
375
- this.data.worksheet.sheetPr[0].tabColor = [{ $: { rgb } }];
381
+ this._data.worksheet.sheetPr = this._data.worksheet.sheetPr ?? [{}];
382
+ this._data.worksheet.sheetPr[0].tabColor = [{ $: { rgb } }];
376
383
  }
377
384
 
378
385
  setZoom(percent: number): void {
379
- this.data.worksheet.sheetViews = this.data.worksheet.sheetViews ?? [
386
+ this._data.worksheet.sheetViews = this._data.worksheet.sheetViews ?? [
380
387
  { sheetView: [{ $: { workbookViewId: "0" } }] },
381
388
  ];
382
389
 
383
- this.data.worksheet.sheetViews[0].sheetView[0].$.zoomScale = percent.toString();
390
+ this._data.worksheet.sheetViews[0].sheetView[0].$.zoomScale = percent.toString();
384
391
  }
385
392
 
386
393
  freezeAt(point: { r?: number; c?: number }): void {
387
- this.data.worksheet.sheetViews = this.data.worksheet.sheetViews ?? [
394
+ this._data.worksheet.sheetViews = this._data.worksheet.sheetViews ?? [
388
395
  { sheetView: [{ $: { workbookViewId: "0" } }] },
389
396
  ];
390
397
 
391
- this.data.worksheet.sheetViews[0].sheetView[0].pane = [
398
+ this._data.worksheet.sheetViews[0].sheetView[0].pane = [
392
399
  {
393
400
  $: {
394
401
  ...(point.c != null
@@ -413,7 +420,7 @@ export class ExcelXmlWorksheet implements ExcelXml {
413
420
  }
414
421
 
415
422
  setAutoFilter(range: ExcelAddressRangePoint): void {
416
- this.data.worksheet.autoFilter = [
423
+ this._data.worksheet.autoFilter = [
417
424
  { $: { ref: ExcelUtils.stringifyRangeAddr(range) } },
418
425
  ];
419
426
  }
@@ -482,12 +489,25 @@ export class ExcelXmlWorksheet implements ExcelXml {
482
489
  }
483
490
  }
484
491
 
485
- cleanup(): void {
492
+ setDrawingRelId(relId: string): void {
493
+ this._data.worksheet.$["xmlns:r"] =
494
+ this._data.worksheet.$["xmlns:r"] ??
495
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
496
+ this._data.worksheet.drawing = this._data.worksheet.drawing ?? [];
497
+ this._data.worksheet.drawing.push({ $: { "r:id": relId } });
498
+ }
499
+
500
+ serialize(): Bytes {
501
+ this._cleanup();
502
+ return new TextEncoder().encode(xmlU.stringify(this._data));
503
+ }
504
+
505
+ private _cleanup(): void {
486
506
  const result = {} as ExcelXmlWorksheetData["worksheet"];
487
507
 
488
508
  // 정렬 순서 ("sheetData" 기준, 나머지는 원래 위치 유지)
489
509
 
490
- for (const key of Object.keys(this.data.worksheet)) {
510
+ for (const key of Object.keys(this._data.worksheet)) {
491
511
  if (key === "mergeCells") continue;
492
512
  if (key === "cols") continue;
493
513
  if (key === "sheetViews") continue;
@@ -499,32 +519,32 @@ export class ExcelXmlWorksheet implements ExcelXml {
499
519
 
500
520
  if (key === "sheetData") {
501
521
  // OOXML CT_Worksheet 자식 순서: sheetPr → dimension → sheetViews → sheetFormatPr → cols → sheetData → autoFilter → mergeCells → conditionalFormatting
502
- if (this.data.worksheet.sheetPr != null) {
503
- result.sheetPr = this.data.worksheet.sheetPr;
522
+ if (this._data.worksheet.sheetPr != null) {
523
+ result.sheetPr = this._data.worksheet.sheetPr;
504
524
  }
505
- result.dimension = this.data.worksheet.dimension ?? [{ $: { ref: "A1" } }];
506
- if (this.data.worksheet.sheetViews != null) {
507
- result.sheetViews = this.data.worksheet.sheetViews;
525
+ result.dimension = this._data.worksheet.dimension ?? [{ $: { ref: "A1" } }];
526
+ if (this._data.worksheet.sheetViews != null) {
527
+ result.sheetViews = this._data.worksheet.sheetViews;
508
528
  }
509
- if (this.data.worksheet.sheetFormatPr != null) {
510
- result.sheetFormatPr = this.data.worksheet.sheetFormatPr;
529
+ if (this._data.worksheet.sheetFormatPr != null) {
530
+ result.sheetFormatPr = this._data.worksheet.sheetFormatPr;
511
531
  }
512
- if (this.data.worksheet.cols != null) {
513
- result.cols = this.data.worksheet.cols;
532
+ if (this._data.worksheet.cols != null) {
533
+ result.cols = this._data.worksheet.cols;
514
534
  }
515
- result.sheetData = this.data.worksheet.sheetData;
535
+ result.sheetData = this._data.worksheet.sheetData;
516
536
 
517
- if (this.data.worksheet.autoFilter != null) {
518
- result.autoFilter = this.data.worksheet.autoFilter;
537
+ if (this._data.worksheet.autoFilter != null) {
538
+ result.autoFilter = this._data.worksheet.autoFilter;
519
539
  }
520
- if (this.data.worksheet.mergeCells != null) {
521
- result.mergeCells = this.data.worksheet.mergeCells;
540
+ if (this._data.worksheet.mergeCells != null) {
541
+ result.mergeCells = this._data.worksheet.mergeCells;
522
542
  }
523
- if (this.data.worksheet.conditionalFormatting != null) {
524
- result.conditionalFormatting = this.data.worksheet.conditionalFormatting;
543
+ if (this._data.worksheet.conditionalFormatting != null) {
544
+ result.conditionalFormatting = this._data.worksheet.conditionalFormatting;
525
545
  }
526
546
  } else {
527
- const worksheetRec = this.data.worksheet as Record<string, unknown>;
547
+ const worksheetRec = this._data.worksheet as Record<string, unknown>;
528
548
  const resultRec = result as Record<string, unknown>;
529
549
  resultRec[key] = worksheetRec[key];
530
550
  }
@@ -547,7 +567,7 @@ export class ExcelXmlWorksheet implements ExcelXml {
547
567
  const dimension = (result.dimension ??= [{ $: { ref: "A1" } }]);
548
568
  dimension[0].$.ref = ExcelUtils.stringifyRangeAddr(this.range);
549
569
 
550
- this.data.worksheet = result;
570
+ this._data.worksheet = result;
551
571
  }
552
572
 
553
573
  private _getCellData(addr: { r: number; c: number }): ExcelCellData | undefined {
@@ -583,8 +603,8 @@ export class ExcelXmlWorksheet implements ExcelXml {
583
603
  this._deleteRow(r);
584
604
 
585
605
  // 시트에 쓰기
586
- this.data.worksheet.sheetData[0].row = this.data.worksheet.sheetData[0].row ?? [];
587
- this.data.worksheet.sheetData[0].row.push(rowData);
606
+ this._data.worksheet.sheetData[0].row = this._data.worksheet.sheetData[0].row ?? [];
607
+ this._data.worksheet.sheetData[0].row.push(rowData);
588
608
 
589
609
  // 캐시에 쓰기
590
610
  const rowInfo = {
@@ -616,7 +636,7 @@ export class ExcelXmlWorksheet implements ExcelXml {
616
636
  private _deleteRow(r: number): void {
617
637
  const targetRowInfo = this._dataMap.get(r);
618
638
  if (targetRowInfo != null) {
619
- const rows = this.data.worksheet.sheetData[0].row;
639
+ const rows = this._data.worksheet.sheetData[0].row;
620
640
  if (rows) {
621
641
  const rowIndex = rows.indexOf(targetRowInfo.data);
622
642
  if (rowIndex !== -1) rows.splice(rowIndex, 1);
@@ -625,8 +645,8 @@ export class ExcelXmlWorksheet implements ExcelXml {
625
645
  this._dataMap.delete(r);
626
646
 
627
647
  // 행이 남아있지 않으면 XML에서 행 섹션 삭제
628
- if (this.data.worksheet.sheetData[0].row?.length === 0) {
629
- delete this.data.worksheet.sheetData[0].row;
648
+ if (this._data.worksheet.sheetData[0].row?.length === 0) {
649
+ delete this._data.worksheet.sheetData[0].row;
630
650
  }
631
651
  }
632
652
  }
@@ -0,0 +1,83 @@
1
+ import type { Bytes } from "@simplysm/core-common";
2
+ import { xml as xmlU } from "@simplysm/core-common";
3
+ import type { ExcelFormat } from "../models/excel-format";
4
+ import type { IExcelModel } from "../models/excel-model";
5
+ import type { IExcelModelFactory } from "../models/excel-model-factory";
6
+ import type { IContentTypeModel } from "../models/i-content-type-model";
7
+ import type { IDrawingModel } from "../models/i-drawing-model";
8
+ import type { IRelationshipModel } from "../models/i-relationship-model";
9
+ import type { ISharedStringModel } from "../models/i-shared-string-model";
10
+ import type { IStyleModel } from "../models/i-style-model";
11
+ import type { IWorkbookModel } from "../models/i-workbook-model";
12
+ import type { IWorksheetModel } from "../models/i-worksheet-model";
13
+ import type {
14
+ ExcelXmlContentTypeData,
15
+ ExcelXmlDrawingData,
16
+ ExcelXmlRelationshipData,
17
+ ExcelXmlSharedStringData,
18
+ ExcelXmlStyleData,
19
+ ExcelXmlWorkbookData,
20
+ ExcelXmlWorksheetData,
21
+ } from "../types";
22
+ import { ExcelXmlContentType } from "./excel-xml-content-type";
23
+ import { ExcelXmlDrawing } from "./excel-xml-drawing";
24
+ import { ExcelXmlRelationship } from "./excel-xml-relationship";
25
+ import { ExcelXmlSharedString } from "./excel-xml-shared-string";
26
+ import { ExcelXmlStyle } from "./excel-xml-style";
27
+ import { ExcelXmlUnknown } from "./excel-xml-unknown";
28
+ import { ExcelXmlWorkbook } from "./excel-xml-workbook";
29
+ import { ExcelXmlWorksheet } from "./excel-xml-worksheet";
30
+
31
+ /** xlsx(OOXML XML) 포맷의 파트 모델 팩토리. */
32
+ export class XmlModelFactory implements IExcelModelFactory {
33
+ readonly format: ExcelFormat = "xlsx";
34
+
35
+ isModelPart(filePath: string): boolean {
36
+ return filePath.endsWith(".xml") || filePath.endsWith(".rels");
37
+ }
38
+
39
+ createWorkbook(): IWorkbookModel {
40
+ return new ExcelXmlWorkbook();
41
+ }
42
+ createWorksheet(): IWorksheetModel {
43
+ return new ExcelXmlWorksheet();
44
+ }
45
+ createStyle(): IStyleModel {
46
+ return new ExcelXmlStyle();
47
+ }
48
+ createSharedString(): ISharedStringModel {
49
+ return new ExcelXmlSharedString();
50
+ }
51
+ createContentType(): IContentTypeModel {
52
+ return new ExcelXmlContentType();
53
+ }
54
+ createRelationship(): IRelationshipModel {
55
+ return new ExcelXmlRelationship();
56
+ }
57
+ createDrawing(): IDrawingModel {
58
+ return new ExcelXmlDrawing();
59
+ }
60
+
61
+ parse(filePath: string, bytes: Bytes): IExcelModel {
62
+ const fileText = new TextDecoder().decode(bytes);
63
+ const xml = xmlU.parse(fileText, { stripTagPrefix: true });
64
+
65
+ if (filePath.endsWith(".rels")) {
66
+ return new ExcelXmlRelationship(xml as ExcelXmlRelationshipData);
67
+ } else if (filePath === "[Content_Types].xml") {
68
+ return new ExcelXmlContentType(xml as ExcelXmlContentTypeData);
69
+ } else if (filePath === "xl/workbook.xml") {
70
+ return new ExcelXmlWorkbook(xml as ExcelXmlWorkbookData);
71
+ } else if (filePath.startsWith("xl/worksheets/sheet") && filePath.endsWith(".xml")) {
72
+ return new ExcelXmlWorksheet(xml as ExcelXmlWorksheetData);
73
+ } else if (filePath.startsWith("xl/drawings/drawing") && filePath.endsWith(".xml")) {
74
+ return new ExcelXmlDrawing(xml as ExcelXmlDrawingData);
75
+ } else if (filePath === "xl/sharedStrings.xml") {
76
+ return new ExcelXmlSharedString(xml as ExcelXmlSharedStringData);
77
+ } else if (filePath === "xl/styles.xml") {
78
+ return new ExcelXmlStyle(xml as ExcelXmlStyleData);
79
+ } else {
80
+ return new ExcelXmlUnknown(xml as Record<string, unknown>);
81
+ }
82
+ }
83
+ }