@simplysm/excel 13.0.99 → 14.0.1

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 (95) hide show
  1. package/dist/excel-cell.d.ts +28 -28
  2. package/dist/excel-cell.d.ts.map +1 -1
  3. package/dist/excel-cell.js +273 -264
  4. package/dist/excel-cell.js.map +1 -6
  5. package/dist/excel-col.d.ts +4 -4
  6. package/dist/excel-col.d.ts.map +1 -1
  7. package/dist/excel-col.js +33 -35
  8. package/dist/excel-col.js.map +1 -6
  9. package/dist/excel-row.d.ts +3 -3
  10. package/dist/excel-row.d.ts.map +1 -1
  11. package/dist/excel-row.js +28 -30
  12. package/dist/excel-row.js.map +1 -6
  13. package/dist/excel-workbook.d.ts +23 -23
  14. package/dist/excel-workbook.d.ts.map +1 -1
  15. package/dist/excel-workbook.js +151 -125
  16. package/dist/excel-workbook.js.map +1 -6
  17. package/dist/excel-worksheet.d.ts +32 -32
  18. package/dist/excel-worksheet.d.ts.map +1 -1
  19. package/dist/excel-worksheet.js +281 -253
  20. package/dist/excel-worksheet.js.map +1 -6
  21. package/dist/excel-wrapper.d.ts +7 -7
  22. package/dist/excel-wrapper.d.ts.map +1 -1
  23. package/dist/excel-wrapper.js +190 -226
  24. package/dist/excel-wrapper.js.map +1 -6
  25. package/dist/index.js +4 -1
  26. package/dist/index.js.map +1 -6
  27. package/dist/types.d.ts +13 -13
  28. package/dist/types.d.ts.map +1 -1
  29. package/dist/types.js +3 -1
  30. package/dist/types.js.map +1 -6
  31. package/dist/utils/excel-utils.d.ts +23 -23
  32. package/dist/utils/excel-utils.d.ts.map +1 -1
  33. package/dist/utils/excel-utils.js +183 -151
  34. package/dist/utils/excel-utils.js.map +1 -6
  35. package/dist/utils/zip-cache.d.ts +6 -6
  36. package/dist/utils/zip-cache.js +78 -60
  37. package/dist/utils/zip-cache.js.map +1 -6
  38. package/dist/xml/excel-xml-content-type.d.ts +2 -2
  39. package/dist/xml/excel-xml-content-type.js +55 -53
  40. package/dist/xml/excel-xml-content-type.js.map +1 -6
  41. package/dist/xml/excel-xml-drawing.d.ts +2 -2
  42. package/dist/xml/excel-xml-drawing.js +74 -73
  43. package/dist/xml/excel-xml-drawing.js.map +1 -6
  44. package/dist/xml/excel-xml-relationship.d.ts +2 -2
  45. package/dist/xml/excel-xml-relationship.js +67 -67
  46. package/dist/xml/excel-xml-relationship.js.map +1 -6
  47. package/dist/xml/excel-xml-shared-string.d.ts +2 -2
  48. package/dist/xml/excel-xml-shared-string.js +57 -55
  49. package/dist/xml/excel-xml-shared-string.js.map +1 -6
  50. package/dist/xml/excel-xml-style.d.ts +2 -2
  51. package/dist/xml/excel-xml-style.js +311 -295
  52. package/dist/xml/excel-xml-style.js.map +1 -6
  53. package/dist/xml/excel-xml-unknown.d.ts +2 -2
  54. package/dist/xml/excel-xml-unknown.js +11 -10
  55. package/dist/xml/excel-xml-unknown.js.map +1 -6
  56. package/dist/xml/excel-xml-workbook.d.ts +2 -2
  57. package/dist/xml/excel-xml-workbook.js +87 -90
  58. package/dist/xml/excel-xml-workbook.js.map +1 -6
  59. package/dist/xml/excel-xml-worksheet.d.ts +6 -6
  60. package/dist/xml/excel-xml-worksheet.js +450 -393
  61. package/dist/xml/excel-xml-worksheet.js.map +1 -6
  62. package/package.json +5 -7
  63. package/src/excel-cell.ts +36 -36
  64. package/src/excel-col.ts +4 -4
  65. package/src/excel-row.ts +3 -3
  66. package/src/excel-workbook.ts +38 -38
  67. package/src/excel-worksheet.ts +69 -51
  68. package/src/excel-wrapper.ts +55 -50
  69. package/src/index.ts +3 -3
  70. package/src/types.ts +17 -17
  71. package/src/utils/excel-utils.ts +47 -41
  72. package/src/utils/zip-cache.ts +6 -6
  73. package/src/xml/excel-xml-content-type.ts +3 -3
  74. package/src/xml/excel-xml-drawing.ts +2 -2
  75. package/src/xml/excel-xml-relationship.ts +3 -3
  76. package/src/xml/excel-xml-shared-string.ts +2 -2
  77. package/src/xml/excel-xml-style.ts +11 -11
  78. package/src/xml/excel-xml-unknown.ts +2 -2
  79. package/src/xml/excel-xml-workbook.ts +5 -5
  80. package/src/xml/excel-xml-worksheet.ts +43 -43
  81. package/README.md +0 -119
  82. package/docs/core-classes.md +0 -541
  83. package/docs/types.md +0 -297
  84. package/docs/utilities.md +0 -128
  85. package/docs/wrapper.md +0 -100
  86. package/tests/excel-cell.spec.ts +0 -393
  87. package/tests/excel-col.spec.ts +0 -81
  88. package/tests/excel-row.spec.ts +0 -61
  89. package/tests/excel-workbook.spec.ts +0 -205
  90. package/tests/excel-worksheet.spec.ts +0 -469
  91. package/tests/excel-wrapper.spec.ts +0 -273
  92. package/tests/fixtures/logo.png +0 -0
  93. package/tests/fixtures//354/264/210/352/270/260/355/231/224.xlsx +0 -0
  94. package/tests/image-insert.spec.ts +0 -190
  95. package/tests/utils/excel-utils.spec.ts +0 -198
@@ -1,426 +1,483 @@
1
1
  import { ExcelUtils } from "../utils/excel-utils.js";
2
2
  import { num, obj } from "@simplysm/core-common";
3
3
  import "@simplysm/core-common";
4
- class ExcelXmlWorksheet {
5
- data;
6
- _dataMap;
7
- constructor(data) {
8
- if (data === void 0) {
9
- this.data = {
10
- worksheet: {
11
- $: {
12
- xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
13
- },
14
- dimension: [
15
- {
16
- $: {
17
- ref: "A1"
18
- }
4
+ /**
5
+ * xl/worksheets/sheet*.xml 파일을 관리하는 클래스.
6
+ * 셀 데이터, 병합, 열 너비, 행 높이 등을 처리한다.
7
+ */
8
+ export class ExcelXmlWorksheet {
9
+ data;
10
+ _dataMap;
11
+ constructor(data) {
12
+ if (data === undefined) {
13
+ this.data = {
14
+ worksheet: {
15
+ $: {
16
+ xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
17
+ },
18
+ dimension: [
19
+ {
20
+ $: {
21
+ ref: "A1",
22
+ },
23
+ },
24
+ ],
25
+ sheetData: [{}],
26
+ },
27
+ };
28
+ }
29
+ else {
30
+ this.data = data;
31
+ }
32
+ this._dataMap = (this.data.worksheet.sheetData[0].row ?? []).toMap((row) => ExcelUtils.parseRowAddr(row.$.r), (row) => ({
33
+ data: row,
34
+ cellMap: (row.c ?? []).toMap((cell) => ExcelUtils.parseColAddr(cell.$.r), (cell) => cell),
35
+ }));
36
+ }
37
+ get range() {
38
+ let maxRow = 0;
39
+ let maxCol = 0;
40
+ for (const [rowIdx, info] of this._dataMap.entries()) {
41
+ if (rowIdx > maxRow)
42
+ maxRow = rowIdx;
43
+ for (const col of info.cellMap.keys()) {
44
+ if (col > maxCol)
45
+ maxCol = col;
19
46
  }
20
- ],
21
- sheetData: [{}]
22
47
  }
23
- };
24
- } else {
25
- this.data = data;
48
+ return {
49
+ s: { r: 0, c: 0 },
50
+ e: { r: maxRow, c: maxCol },
51
+ };
26
52
  }
27
- this._dataMap = (this.data.worksheet.sheetData[0].row ?? []).toMap(
28
- (row) => ExcelUtils.parseRowAddr(row.$.r),
29
- (row) => ({
30
- data: row,
31
- cellMap: (row.c ?? []).toMap(
32
- (cell) => ExcelUtils.parseColAddr(cell.$.r),
33
- (cell) => cell
34
- )
35
- })
36
- );
37
- }
38
- get range() {
39
- let maxRow = 0;
40
- let maxCol = 0;
41
- for (const [rowIdx, info] of this._dataMap.entries()) {
42
- if (rowIdx > maxRow) maxRow = rowIdx;
43
- for (const col of info.cellMap.keys()) {
44
- if (col > maxCol) maxCol = col;
45
- }
53
+ setCellType(addr, type) {
54
+ const cellData = this._getOrCreateCellData(addr);
55
+ if (type != null) {
56
+ cellData.$.t = type;
57
+ }
58
+ else {
59
+ delete cellData.$.t;
60
+ }
46
61
  }
47
- return {
48
- s: { r: 0, c: 0 },
49
- e: { r: maxRow, c: maxCol }
50
- };
51
- }
52
- setCellType(addr, type) {
53
- const cellData = this._getOrCreateCellData(addr);
54
- if (type != null) {
55
- cellData.$.t = type;
56
- } else {
57
- delete cellData.$.t;
62
+ getCellType(addr) {
63
+ return this._getCellData(addr)?.$.t;
58
64
  }
59
- }
60
- getCellType(addr) {
61
- var _a;
62
- return (_a = this._getCellData(addr)) == null ? void 0 : _a.$.t;
63
- }
64
- setCellVal(addr, val) {
65
- const cellData = this._getOrCreateCellData(addr);
66
- if (val === void 0) {
67
- delete cellData.v;
68
- } else {
69
- cellData.v = [val];
65
+ setCellVal(addr, val) {
66
+ const cellData = this._getOrCreateCellData(addr);
67
+ if (val === undefined) {
68
+ delete cellData.v;
69
+ }
70
+ else {
71
+ cellData.v = [val];
72
+ }
70
73
  }
71
- }
72
- getCellVal(addr) {
73
- var _a, _b, _c, _d;
74
- const cellData = this._getCellData(addr);
75
- const tVal = (_c = (_b = (_a = cellData == null ? void 0 : cellData.is) == null ? void 0 : _a[0]) == null ? void 0 : _b.t) == null ? void 0 : _c[0];
76
- const val = ((_d = cellData == null ? void 0 : cellData.v) == null ? void 0 : _d[0]) ?? (typeof tVal === "string" ? tVal : tVal == null ? void 0 : tVal._);
77
- return typeof val === "string" ? val : void 0;
78
- }
79
- setCellFormula(addr, val) {
80
- const cellData = this._getOrCreateCellData(addr);
81
- if (val === void 0) {
82
- delete cellData.f;
83
- } else {
84
- cellData.f = [val];
74
+ getCellVal(addr) {
75
+ const cellData = this._getCellData(addr);
76
+ const tVal = cellData?.is?.[0]?.t?.[0];
77
+ const val = cellData?.v?.[0] ?? (typeof tVal === "string" ? tVal : tVal?._);
78
+ return typeof val === "string" ? val : undefined;
85
79
  }
86
- }
87
- getCellFormula(addr) {
88
- var _a, _b;
89
- const val = (_b = (_a = this._getCellData(addr)) == null ? void 0 : _a.f) == null ? void 0 : _b[0];
90
- return typeof val === "string" ? val : void 0;
91
- }
92
- getCellStyleId(addr) {
93
- var _a;
94
- return (_a = this._getCellData(addr)) == null ? void 0 : _a.$.s;
95
- }
96
- setCellStyleId(addr, styleId) {
97
- if (styleId != null) {
98
- this._getOrCreateCellData(addr).$.s = styleId;
99
- } else {
100
- delete this._getOrCreateCellData(addr).$.s;
80
+ setCellFormula(addr, val) {
81
+ const cellData = this._getOrCreateCellData(addr);
82
+ if (val === undefined) {
83
+ delete cellData.f;
84
+ }
85
+ else {
86
+ cellData.f = [val];
87
+ }
101
88
  }
102
- }
103
- deleteCell(addr) {
104
- const rowInfo = this._dataMap.get(addr.r);
105
- if (rowInfo == null) return;
106
- const cellData = rowInfo.cellMap.get(addr.c);
107
- if (cellData == null) return;
108
- const cellsData = rowInfo.data.c;
109
- const cellIndex = cellsData.indexOf(cellData);
110
- if (cellIndex !== -1) cellsData.splice(cellIndex, 1);
111
- rowInfo.cellMap.delete(addr.c);
112
- if (rowInfo.cellMap.size === 0) {
113
- this._deleteRow(addr.r);
89
+ getCellFormula(addr) {
90
+ const val = this._getCellData(addr)?.f?.[0];
91
+ return typeof val === "string" ? val : undefined;
114
92
  }
115
- }
116
- setMergeCells(startAddr, endAddr) {
117
- const mergeCells = this.data.worksheet.mergeCells = this.data.worksheet.mergeCells ?? [
118
- {
119
- $: { count: "0" },
120
- mergeCell: []
121
- }
122
- ];
123
- const newRange = { s: startAddr, e: endAddr };
124
- const existingMergeCells = mergeCells[0].mergeCell;
125
- for (const mergeCell of existingMergeCells) {
126
- const existingRange = ExcelUtils.parseRangeAddr(mergeCell.$.ref);
127
- if (newRange.s.r <= existingRange.e.r && newRange.e.r >= existingRange.s.r && newRange.s.c <= existingRange.e.c && newRange.e.c >= existingRange.s.c) {
128
- throw new Error(
129
- `Merged cell overlaps with existing merge range (${mergeCell.$.ref}): ${ExcelUtils.stringifyRangeAddr(newRange)}`
130
- );
131
- }
93
+ getCellStyleId(addr) {
94
+ return this._getCellData(addr)?.$.s;
132
95
  }
133
- mergeCells[0].mergeCell.push({ $: { ref: ExcelUtils.stringifyRangeAddr(newRange) } });
134
- mergeCells[0].$.count = mergeCells[0].mergeCell.length.toString();
135
- for (let r = startAddr.r; r <= endAddr.r; r++) {
136
- for (let c = startAddr.c; c <= endAddr.c; c++) {
137
- const currentAddr = { r, c };
138
- if (currentAddr.r !== startAddr.r || currentAddr.c !== startAddr.c) {
139
- this.deleteCell(currentAddr);
140
- }
141
- }
96
+ setCellStyleId(addr, styleId) {
97
+ if (styleId != null) {
98
+ this._getOrCreateCellData(addr).$.s = styleId;
99
+ }
100
+ else {
101
+ delete this._getOrCreateCellData(addr).$.s;
102
+ }
142
103
  }
143
- }
144
- getMergeCells() {
145
- const mergeCells = this.data.worksheet.mergeCells;
146
- if (mergeCells === void 0) return [];
147
- return mergeCells[0].mergeCell.map((item) => ExcelUtils.parseRangeAddr(item.$.ref));
148
- }
149
- removeMergeCells(fromAddr, toAddr) {
150
- if (this.data.worksheet.mergeCells == null) return;
151
- const range = { s: fromAddr, e: toAddr };
152
- const filteredMergeCells = this.data.worksheet.mergeCells[0].mergeCell.filter((item) => {
153
- const rangeAddr = ExcelUtils.parseRangeAddr(item.$.ref);
154
- return !(rangeAddr.s.r >= range.s.r && rangeAddr.e.r <= range.e.r && rangeAddr.s.c >= range.s.c && rangeAddr.e.c <= range.e.c);
155
- });
156
- if (filteredMergeCells.length === 0) {
157
- delete this.data.worksheet.mergeCells;
158
- } else {
159
- this.data.worksheet.mergeCells[0].mergeCell = filteredMergeCells;
160
- this.data.worksheet.mergeCells[0].$.count = filteredMergeCells.length.toString();
104
+ deleteCell(addr) {
105
+ // 행이 존재하지 않으면 아무 작업도 하지 않음
106
+ const rowInfo = this._dataMap.get(addr.r);
107
+ if (rowInfo == null)
108
+ return;
109
+ // 셀이 존재하지 않으면 아무 작업도 하지 않음
110
+ const cellData = rowInfo.cellMap.get(addr.c);
111
+ if (cellData == null)
112
+ return;
113
+ // 삭제
114
+ const cellsData = rowInfo.data.c;
115
+ const cellIndex = cellsData.indexOf(cellData);
116
+ if (cellIndex !== -1)
117
+ cellsData.splice(cellIndex, 1);
118
+ rowInfo.cellMap.delete(addr.c);
119
+ // 마지막 셀이었으면 행도 삭제
120
+ if (rowInfo.cellMap.size === 0) {
121
+ this._deleteRow(addr.r);
122
+ }
161
123
  }
162
- }
163
- shiftMergeCells(fromRow, delta) {
164
- const mergeCells = this.data.worksheet.mergeCells;
165
- if (mergeCells === void 0) return;
166
- for (const mergeCell of mergeCells[0].mergeCell) {
167
- const range = ExcelUtils.parseRangeAddr(mergeCell.$.ref);
168
- if (range.s.r >= fromRow) {
169
- range.s.r += delta;
170
- }
171
- if (range.e.r >= fromRow) {
172
- range.e.r += delta;
173
- }
174
- mergeCell.$.ref = ExcelUtils.stringifyRangeAddr(range);
124
+ setMergeCells(startAddr, endAddr) {
125
+ const mergeCells = (this.data.worksheet.mergeCells = this.data.worksheet.mergeCells ?? [
126
+ {
127
+ $: { count: "0" },
128
+ mergeCell: [],
129
+ },
130
+ ]);
131
+ const newRange = { s: startAddr, e: endAddr };
132
+ // 병합 겹침 검사
133
+ const existingMergeCells = mergeCells[0].mergeCell;
134
+ for (const mergeCell of existingMergeCells) {
135
+ const existingRange = ExcelUtils.parseRangeAddr(mergeCell.$.ref);
136
+ if (newRange.s.r <= existingRange.e.r &&
137
+ newRange.e.r >= existingRange.s.r &&
138
+ newRange.s.c <= existingRange.e.c &&
139
+ newRange.e.c >= existingRange.s.c) {
140
+ throw new Error(`셀 병합이 기존 병합 범위와 겹칩니다 (${mergeCell.$.ref}): ${ExcelUtils.stringifyRangeAddr(newRange)}`);
141
+ }
142
+ }
143
+ mergeCells[0].mergeCell.push({ $: { ref: ExcelUtils.stringifyRangeAddr(newRange) } });
144
+ mergeCells[0].$.count = mergeCells[0].mergeCell.length.toString();
145
+ // 시작 셀을 제외한 모든 셀 삭제
146
+ for (let r = startAddr.r; r <= endAddr.r; r++) {
147
+ for (let c = startAddr.c; c <= endAddr.c; c++) {
148
+ const currentAddr = { r, c };
149
+ if (currentAddr.r !== startAddr.r || currentAddr.c !== startAddr.c) {
150
+ this.deleteCell(currentAddr);
151
+ }
152
+ }
153
+ }
175
154
  }
176
- }
177
- /**
178
- * Set width of a specific column.
179
- *
180
- * @internal
181
- * Use ExcelCol.setWidth() externally.
182
- *
183
- * @param colIndex Column index (1-based, string)
184
- * @param width Width to set
185
- */
186
- setColWidth(colIndex, width) {
187
- var _a;
188
- const colIndexNumber = num.parseInt(colIndex);
189
- if (colIndexNumber == null) {
190
- throw new Error(`Invalid column index: ${colIndex}`);
155
+ getMergeCells() {
156
+ const mergeCells = this.data.worksheet.mergeCells;
157
+ if (mergeCells === undefined)
158
+ return [];
159
+ return mergeCells[0].mergeCell.map((item) => ExcelUtils.parseRangeAddr(item.$.ref));
191
160
  }
192
- const cols = (_a = this.data.worksheet.cols) == null ? void 0 : _a[0];
193
- const col = cols ? cols.col.single(
194
- (item) => (num.parseInt(item.$.min) ?? 0) <= colIndexNumber && (num.parseInt(item.$.max) ?? 0) >= colIndexNumber
195
- ) : void 0;
196
- if (col != null && cols != null) {
197
- if (col.$.min === col.$.max) {
198
- col.$.bestFit = "1";
199
- col.$.customWidth = "1";
200
- col.$.width = width;
201
- } else {
202
- const minNumber = num.parseInt(col.$.min) ?? 0;
203
- const maxNumber = num.parseInt(col.$.max) ?? 0;
204
- let insertIndex = cols.col.indexOf(col);
205
- if (minNumber < colIndexNumber) {
206
- cols.col.splice(insertIndex, 0, {
207
- $: {
208
- ...col.$,
209
- min: col.$.min,
210
- max: (colIndexNumber - 1).toString()
211
- }
212
- });
213
- insertIndex++;
214
- }
215
- cols.col.splice(insertIndex, 0, {
216
- $: {
217
- min: colIndex,
218
- max: colIndex,
219
- bestFit: "1",
220
- customWidth: "1",
221
- width
222
- }
161
+ removeMergeCells(fromAddr, toAddr) {
162
+ if (this.data.worksheet.mergeCells == null)
163
+ return;
164
+ const range = { s: fromAddr, e: toAddr };
165
+ const filteredMergeCells = this.data.worksheet.mergeCells[0].mergeCell.filter((item) => {
166
+ const rangeAddr = ExcelUtils.parseRangeAddr(item.$.ref);
167
+ return !(rangeAddr.s.r >= range.s.r &&
168
+ rangeAddr.e.r <= range.e.r &&
169
+ rangeAddr.s.c >= range.s.c &&
170
+ rangeAddr.e.c <= range.e.c);
223
171
  });
224
- insertIndex++;
225
- if (maxNumber > colIndexNumber) {
226
- cols.col.splice(insertIndex, 0, {
227
- $: {
228
- ...col.$,
229
- min: (colIndexNumber + 1).toString(),
230
- max: col.$.max
172
+ if (filteredMergeCells.length === 0) {
173
+ delete this.data.worksheet.mergeCells;
174
+ }
175
+ else {
176
+ this.data.worksheet.mergeCells[0].mergeCell = filteredMergeCells;
177
+ this.data.worksheet.mergeCells[0].$.count = filteredMergeCells.length.toString();
178
+ }
179
+ }
180
+ shiftMergeCells(fromRow, delta) {
181
+ const mergeCells = this.data.worksheet.mergeCells;
182
+ if (mergeCells === undefined)
183
+ return;
184
+ for (const mergeCell of mergeCells[0].mergeCell) {
185
+ const range = ExcelUtils.parseRangeAddr(mergeCell.$.ref);
186
+ if (range.s.r >= fromRow) {
187
+ range.s.r += delta;
231
188
  }
232
- });
233
- }
234
- const colIndex2 = cols.col.indexOf(col);
235
- if (colIndex2 !== -1) cols.col.splice(colIndex2, 1);
236
- }
237
- } else {
238
- this.data.worksheet.cols = this.data.worksheet.cols ?? [{ col: [] }];
239
- this.data.worksheet.cols[0].col.push({
240
- $: {
241
- min: colIndex,
242
- max: colIndex,
243
- bestFit: "1",
244
- customWidth: "1",
245
- width
246
- }
247
- });
189
+ if (range.e.r >= fromRow) {
190
+ range.e.r += delta;
191
+ }
192
+ mergeCell.$.ref = ExcelUtils.stringifyRangeAddr(range);
193
+ }
248
194
  }
249
- }
250
- setZoom(percent) {
251
- this.data.worksheet.sheetViews = this.data.worksheet.sheetViews ?? [
252
- { sheetView: [{ $: { workbookViewId: "0" } }] }
253
- ];
254
- this.data.worksheet.sheetViews[0].sheetView[0].$.zoomScale = percent.toString();
255
- }
256
- freezeAt(point) {
257
- this.data.worksheet.sheetViews = this.data.worksheet.sheetViews ?? [
258
- { sheetView: [{ $: { workbookViewId: "0" } }] }
259
- ];
260
- this.data.worksheet.sheetViews[0].sheetView[0].pane = [
261
- {
262
- $: {
263
- ...point.c != null ? {
264
- xSplit: (point.c + 1).toString()
265
- } : {},
266
- ...point.r != null ? {
267
- ySplit: (point.r + 1).toString()
268
- } : {},
269
- topLeftCell: ExcelUtils.stringifyAddr({
270
- r: (point.r ?? -1) + 1,
271
- c: (point.c ?? -1) + 1
272
- }),
273
- activePane: point.r == null ? "topRight" : point.c == null ? "bottomLeft" : "bottomRight",
274
- state: "frozen"
275
- }
276
- }
277
- ];
278
- }
279
- copyRow(sourceR, targetR, options) {
280
- const sourceRowInfo = this._dataMap.get(sourceR);
281
- if (sourceRowInfo != null) {
282
- const newRowData = obj.clone(sourceRowInfo.data);
283
- newRowData.$.r = ExcelUtils.stringifyRowAddr(targetR);
284
- if (newRowData.c != null) {
285
- for (const cellData of newRowData.c) {
286
- const colAddr = ExcelUtils.parseColAddr(cellData.$.r);
287
- cellData.$.r = ExcelUtils.stringifyAddr({ r: targetR, c: colAddr });
288
- }
289
- }
290
- this._replaceRowData(targetR, newRowData);
291
- } else {
292
- this._deleteRow(targetR);
195
+ /**
196
+ * 특정 열의 너비를 설정한다.
197
+ *
198
+ * @internal
199
+ * 외부에서는 ExcelCol.setWidth()를 사용할 것.
200
+ *
201
+ * @param colIndex 열 인덱스 (1 기반, 문자열)
202
+ * @param width 설정할 너비
203
+ */
204
+ setColWidth(colIndex, width) {
205
+ const colIndexNumber = num.parseInt(colIndex);
206
+ if (colIndexNumber == null) {
207
+ throw new Error(`잘못된 열 인덱스: ${colIndex}`);
208
+ }
209
+ const cols = this.data.worksheet.cols?.[0];
210
+ // 대상 열을 포함하는 기존 범위 찾기
211
+ const col = cols
212
+ ? cols.col.single((item) => (num.parseInt(item.$.min) ?? 0) <= colIndexNumber &&
213
+ (num.parseInt(item.$.max) ?? 0) >= colIndexNumber)
214
+ : undefined;
215
+ if (col != null && cols != null) {
216
+ if (col.$.min === col.$.max) {
217
+ // 단일 범위: 해당 열의 속성만 갱신
218
+ col.$.bestFit = "1";
219
+ col.$.customWidth = "1";
220
+ col.$.width = width;
221
+ }
222
+ else {
223
+ // 다중 열 범위: 범위를 분할하고 대상 열에만 새 너비 적용
224
+ // 예: 기존 [1~5, width=10], 대상=3, 새 너비=20
225
+ // -> [1~2, width=10], [3, width=20], [4~5, width=10]
226
+ const minNumber = num.parseInt(col.$.min) ?? 0;
227
+ const maxNumber = num.parseInt(col.$.max) ?? 0;
228
+ let insertIndex = cols.col.indexOf(col);
229
+ // 앞쪽 범위 생성 (min ~ colIndex-1): 원래 속성 유지
230
+ if (minNumber < colIndexNumber) {
231
+ cols.col.splice(insertIndex, 0, {
232
+ $: {
233
+ ...col.$,
234
+ min: col.$.min,
235
+ max: (colIndexNumber - 1).toString(),
236
+ },
237
+ });
238
+ insertIndex++;
239
+ }
240
+ // 대상 열 생성 (colIndex): 새 너비 적용
241
+ cols.col.splice(insertIndex, 0, {
242
+ $: {
243
+ min: colIndex,
244
+ max: colIndex,
245
+ bestFit: "1",
246
+ customWidth: "1",
247
+ width: width,
248
+ },
249
+ });
250
+ insertIndex++;
251
+ // 뒤쪽 범위 생성 (colIndex+1 ~ max): 원래 속성 유지
252
+ if (maxNumber > colIndexNumber) {
253
+ cols.col.splice(insertIndex, 0, {
254
+ $: {
255
+ ...col.$,
256
+ min: (colIndexNumber + 1).toString(),
257
+ max: col.$.max,
258
+ },
259
+ });
260
+ }
261
+ // 원래 범위 삭제
262
+ const colIndex2 = cols.col.indexOf(col);
263
+ if (colIndex2 !== -1)
264
+ cols.col.splice(colIndex2, 1);
265
+ }
266
+ }
267
+ else {
268
+ // 기존 범위 없음: 새 범위 생성
269
+ this.data.worksheet.cols = this.data.worksheet.cols ?? [{ col: [] }];
270
+ this.data.worksheet.cols[0].col.push({
271
+ $: {
272
+ min: colIndex,
273
+ max: colIndex,
274
+ bestFit: "1",
275
+ customWidth: "1",
276
+ width: width,
277
+ },
278
+ });
279
+ }
293
280
  }
294
- if ((options == null ? void 0 : options.skipMerge) === true) {
295
- return;
281
+ setZoom(percent) {
282
+ this.data.worksheet.sheetViews = this.data.worksheet.sheetViews ?? [
283
+ { sheetView: [{ $: { workbookViewId: "0" } }] },
284
+ ];
285
+ this.data.worksheet.sheetViews[0].sheetView[0].$.zoomScale = percent.toString();
296
286
  }
297
- const allMergeCells = this.getMergeCells();
298
- const sourceMergeCells = allMergeCells.filter((mc) => mc.s.r <= sourceR && mc.e.r >= sourceR).map((mc) => ({ s: { ...mc.s }, e: { ...mc.e } }));
299
- for (const mergeCell of allMergeCells) {
300
- if (mergeCell.s.r <= targetR && mergeCell.e.r >= targetR) {
301
- this.removeMergeCells(mergeCell.s, mergeCell.e);
302
- }
287
+ freezeAt(point) {
288
+ this.data.worksheet.sheetViews = this.data.worksheet.sheetViews ?? [
289
+ { sheetView: [{ $: { workbookViewId: "0" } }] },
290
+ ];
291
+ this.data.worksheet.sheetViews[0].sheetView[0].pane = [
292
+ {
293
+ $: {
294
+ ...(point.c != null
295
+ ? {
296
+ xSplit: (point.c + 1).toString(),
297
+ }
298
+ : {}),
299
+ ...(point.r != null
300
+ ? {
301
+ ySplit: (point.r + 1).toString(),
302
+ }
303
+ : {}),
304
+ topLeftCell: ExcelUtils.stringifyAddr({
305
+ r: (point.r ?? -1) + 1,
306
+ c: (point.c ?? -1) + 1,
307
+ }),
308
+ activePane: point.r == null ? "topRight" : point.c == null ? "bottomLeft" : "bottomRight",
309
+ state: "frozen",
310
+ },
311
+ },
312
+ ];
303
313
  }
304
- for (const mergeCell of sourceMergeCells) {
305
- const rowDiff = targetR - sourceR;
306
- const newStartAddr = { r: mergeCell.s.r + rowDiff, c: mergeCell.s.c };
307
- const newEndAddr = { r: mergeCell.e.r + rowDiff, c: mergeCell.e.c };
308
- this.setMergeCells(newStartAddr, newEndAddr);
314
+ copyRow(sourceR, targetR, options) {
315
+ // 원본 데이터 복제
316
+ const sourceRowInfo = this._dataMap.get(sourceR);
317
+ if (sourceRowInfo != null) {
318
+ // 행 데이터 복제
319
+ const newRowData = obj.clone(sourceRowInfo.data);
320
+ // 행 주소 갱신
321
+ newRowData.$.r = ExcelUtils.stringifyRowAddr(targetR);
322
+ // 각 셀 주소 갱신
323
+ if (newRowData.c != null) {
324
+ for (const cellData of newRowData.c) {
325
+ const colAddr = ExcelUtils.parseColAddr(cellData.$.r);
326
+ cellData.$.r = ExcelUtils.stringifyAddr({ r: targetR, c: colAddr });
327
+ }
328
+ }
329
+ this._replaceRowData(targetR, newRowData);
330
+ }
331
+ else {
332
+ this._deleteRow(targetR);
333
+ }
334
+ // skipMerge 옵션이 true이면 병합 처리 건너뛰기
335
+ if (options?.skipMerge === true) {
336
+ return;
337
+ }
338
+ const allMergeCells = this.getMergeCells();
339
+ // 원본 행의 병합 셀 정보를 먼저 복사하여 저장
340
+ const sourceMergeCells = allMergeCells
341
+ .filter((mc) => mc.s.r <= sourceR && mc.e.r >= sourceR)
342
+ .map((mc) => ({ s: { ...mc.s }, e: { ...mc.e } }));
343
+ // 대상 행의 기존 병합 셀 제거
344
+ for (const mergeCell of allMergeCells) {
345
+ if (mergeCell.s.r <= targetR && mergeCell.e.r >= targetR) {
346
+ this.removeMergeCells(mergeCell.s, mergeCell.e);
347
+ }
348
+ }
349
+ // 저장된 원본 병합 정보를 대상에 복사
350
+ for (const mergeCell of sourceMergeCells) {
351
+ const rowDiff = targetR - sourceR;
352
+ const newStartAddr = { r: mergeCell.s.r + rowDiff, c: mergeCell.s.c };
353
+ const newEndAddr = { r: mergeCell.e.r + rowDiff, c: mergeCell.e.c };
354
+ this.setMergeCells(newStartAddr, newEndAddr);
355
+ }
309
356
  }
310
- }
311
- copyCell(sourceAddr, targetAddr) {
312
- const sourceCellData = this._getCellData(sourceAddr);
313
- if (sourceCellData != null) {
314
- const newCellData = obj.clone(sourceCellData);
315
- newCellData.$.r = ExcelUtils.stringifyAddr(targetAddr);
316
- this._replaceCellData(targetAddr, newCellData);
317
- } else {
318
- this.deleteCell(targetAddr);
357
+ copyCell(sourceAddr, targetAddr) {
358
+ const sourceCellData = this._getCellData(sourceAddr);
359
+ if (sourceCellData != null) {
360
+ const newCellData = obj.clone(sourceCellData);
361
+ newCellData.$.r = ExcelUtils.stringifyAddr(targetAddr);
362
+ this._replaceCellData(targetAddr, newCellData);
363
+ }
364
+ else {
365
+ this.deleteCell(targetAddr);
366
+ }
319
367
  }
320
- }
321
- cleanup() {
322
- const result = {};
323
- for (const key of Object.keys(this.data.worksheet)) {
324
- if (key === "mergeCells") continue;
325
- if (key === "cols") continue;
326
- if (key === "sheetViews") continue;
327
- if (key === "sheetFormatPr") continue;
328
- if (key === "sheetData") {
329
- if (this.data.worksheet.sheetViews != null) {
330
- result.sheetViews = this.data.worksheet.sheetViews;
331
- }
332
- if (this.data.worksheet.sheetFormatPr != null) {
333
- result.sheetFormatPr = this.data.worksheet.sheetFormatPr;
334
- }
335
- if (this.data.worksheet.cols != null) {
336
- result.cols = this.data.worksheet.cols;
337
- }
338
- result.sheetData = this.data.worksheet.sheetData;
339
- if (this.data.worksheet.mergeCells != null) {
340
- result.mergeCells = this.data.worksheet.mergeCells;
341
- }
342
- } else {
343
- const worksheetRec = this.data.worksheet;
344
- const resultRec = result;
345
- resultRec[key] = worksheetRec[key];
346
- }
368
+ cleanup() {
369
+ const result = {};
370
+ // 정렬 순서 ("sheetData" 기준, 나머지는 원래 위치 유지)
371
+ for (const key of Object.keys(this.data.worksheet)) {
372
+ if (key === "mergeCells")
373
+ continue;
374
+ if (key === "cols")
375
+ continue;
376
+ if (key === "sheetViews")
377
+ continue;
378
+ if (key === "sheetFormatPr")
379
+ continue;
380
+ if (key === "sheetData") {
381
+ if (this.data.worksheet.sheetViews != null) {
382
+ result.sheetViews = this.data.worksheet.sheetViews;
383
+ }
384
+ if (this.data.worksheet.sheetFormatPr != null) {
385
+ result.sheetFormatPr = this.data.worksheet.sheetFormatPr;
386
+ }
387
+ if (this.data.worksheet.cols != null) {
388
+ result.cols = this.data.worksheet.cols;
389
+ }
390
+ result.sheetData = this.data.worksheet.sheetData;
391
+ if (this.data.worksheet.mergeCells != null) {
392
+ result.mergeCells = this.data.worksheet.mergeCells;
393
+ }
394
+ }
395
+ else {
396
+ const worksheetRec = this.data.worksheet;
397
+ const resultRec = result;
398
+ resultRec[key] = worksheetRec[key];
399
+ }
400
+ }
401
+ // 행 정렬
402
+ const rowsData = (result.sheetData[0].row = result.sheetData[0].row ?? []);
403
+ rowsData.sort((a, b) => (num.parseInt(a.$.r) ?? 0) - (num.parseInt(b.$.r) ?? 0));
404
+ // 셀 정렬
405
+ for (const rowData of rowsData) {
406
+ const cellsData = rowData.c;
407
+ if (cellsData == null)
408
+ continue;
409
+ cellsData.sort((a, b) => ExcelUtils.parseCellAddr(a.$.r).c - ExcelUtils.parseCellAddr(b.$.r).c);
410
+ }
411
+ // dimension 값 적용
412
+ if (result.dimension != null) {
413
+ result.dimension[0].$.ref = ExcelUtils.stringifyRangeAddr(this.range);
414
+ }
415
+ else {
416
+ result.dimension = [{ $: { ref: ExcelUtils.stringifyRangeAddr(this.range) } }];
417
+ }
418
+ this.data.worksheet = result;
347
419
  }
348
- const rowsData = result.sheetData[0].row = result.sheetData[0].row ?? [];
349
- rowsData.sort((a, b) => (num.parseInt(a.$.r) ?? 0) - (num.parseInt(b.$.r) ?? 0));
350
- for (const rowData of rowsData) {
351
- const cellsData = rowData.c;
352
- if (cellsData == null) continue;
353
- cellsData.sort(
354
- (a, b) => ExcelUtils.parseCellAddr(a.$.r).c - ExcelUtils.parseCellAddr(b.$.r).c
355
- );
420
+ _getCellData(addr) {
421
+ return this._dataMap.get(addr.r)?.cellMap.get(addr.c);
356
422
  }
357
- if (result.dimension != null) {
358
- result.dimension[0].$.ref = ExcelUtils.stringifyRangeAddr(this.range);
359
- } else {
360
- result.dimension = [{ $: { ref: ExcelUtils.stringifyRangeAddr(this.range) } }];
423
+ _getOrCreateCellData(addr) {
424
+ // 행이 존재하지 않으면 생성
425
+ const rowInfo = this._getOrCreateRowInfo(addr.r);
426
+ // 셀이 존재하지 않으면 생성
427
+ let cellData = rowInfo.cellMap.get(addr.c);
428
+ if (cellData === undefined) {
429
+ rowInfo.data.c = rowInfo.data.c ?? [];
430
+ cellData = { $: { r: ExcelUtils.stringifyAddr(addr) }, v: [""] };
431
+ rowInfo.data.c.push(cellData);
432
+ rowInfo.cellMap.set(addr.c, cellData);
433
+ }
434
+ return cellData;
361
435
  }
362
- this.data.worksheet = result;
363
- }
364
- _getCellData(addr) {
365
- var _a;
366
- return (_a = this._dataMap.get(addr.r)) == null ? void 0 : _a.cellMap.get(addr.c);
367
- }
368
- _getOrCreateCellData(addr) {
369
- const rowInfo = this._getOrCreateRowInfo(addr.r);
370
- let cellData = rowInfo.cellMap.get(addr.c);
371
- if (cellData === void 0) {
372
- rowInfo.data.c = rowInfo.data.c ?? [];
373
- cellData = { $: { r: ExcelUtils.stringifyAddr(addr) }, v: [""] };
374
- rowInfo.data.c.push(cellData);
375
- rowInfo.cellMap.set(addr.c, cellData);
436
+ _getOrCreateRowInfo(r) {
437
+ const rowInfo = this._dataMap.get(r);
438
+ if (rowInfo == null) {
439
+ return this._replaceRowData(r, { $: { r: ExcelUtils.stringifyRowAddr(r) }, c: [] });
440
+ }
441
+ return rowInfo;
376
442
  }
377
- return cellData;
378
- }
379
- _getOrCreateRowInfo(r) {
380
- const rowInfo = this._dataMap.get(r);
381
- if (rowInfo == null) {
382
- return this._replaceRowData(r, { $: { r: ExcelUtils.stringifyRowAddr(r) }, c: [] });
443
+ _replaceRowData(r, rowData) {
444
+ this._deleteRow(r);
445
+ // 시트에 쓰기
446
+ this.data.worksheet.sheetData[0].row = this.data.worksheet.sheetData[0].row ?? [];
447
+ this.data.worksheet.sheetData[0].row.push(rowData);
448
+ // 캐시에 쓰기
449
+ const rowInfo = {
450
+ data: rowData,
451
+ cellMap: (rowData.c ?? []).toMap((cell) => ExcelUtils.parseColAddr(cell.$.r), (cell) => cell),
452
+ };
453
+ this._dataMap.set(r, rowInfo);
454
+ return rowInfo;
383
455
  }
384
- return rowInfo;
385
- }
386
- _replaceRowData(r, rowData) {
387
- this._deleteRow(r);
388
- this.data.worksheet.sheetData[0].row = this.data.worksheet.sheetData[0].row ?? [];
389
- this.data.worksheet.sheetData[0].row.push(rowData);
390
- const rowInfo = {
391
- data: rowData,
392
- cellMap: (rowData.c ?? []).toMap(
393
- (cell) => ExcelUtils.parseColAddr(cell.$.r),
394
- (cell) => cell
395
- )
396
- };
397
- this._dataMap.set(r, rowInfo);
398
- return rowInfo;
399
- }
400
- _replaceCellData(addr, cellData) {
401
- this.deleteCell(addr);
402
- const targetRowInfo = this._getOrCreateRowInfo(addr.r);
403
- targetRowInfo.data.c = targetRowInfo.data.c ?? [];
404
- targetRowInfo.data.c.push(cellData);
405
- targetRowInfo.cellMap.set(addr.c, cellData);
406
- }
407
- _deleteRow(r) {
408
- var _a;
409
- const targetRowInfo = this._dataMap.get(r);
410
- if (targetRowInfo != null) {
411
- const rows = this.data.worksheet.sheetData[0].row;
412
- if (rows) {
413
- const rowIndex = rows.indexOf(targetRowInfo.data);
414
- if (rowIndex !== -1) rows.splice(rowIndex, 1);
415
- }
456
+ _replaceCellData(addr, cellData) {
457
+ this.deleteCell(addr);
458
+ //
459
+ const targetRowInfo = this._getOrCreateRowInfo(addr.r);
460
+ // 시트에 쓰기
461
+ targetRowInfo.data.c = targetRowInfo.data.c ?? [];
462
+ targetRowInfo.data.c.push(cellData);
463
+ // 캐시에 쓰기
464
+ targetRowInfo.cellMap.set(addr.c, cellData);
416
465
  }
417
- this._dataMap.delete(r);
418
- if (((_a = this.data.worksheet.sheetData[0].row) == null ? void 0 : _a.length) === 0) {
419
- delete this.data.worksheet.sheetData[0].row;
466
+ _deleteRow(r) {
467
+ const targetRowInfo = this._dataMap.get(r);
468
+ if (targetRowInfo != null) {
469
+ const rows = this.data.worksheet.sheetData[0].row;
470
+ if (rows) {
471
+ const rowIndex = rows.indexOf(targetRowInfo.data);
472
+ if (rowIndex !== -1)
473
+ rows.splice(rowIndex, 1);
474
+ }
475
+ }
476
+ this._dataMap.delete(r);
477
+ // 행이 남아있지 않으면 XML에서 행 섹션 삭제
478
+ if (this.data.worksheet.sheetData[0].row?.length === 0) {
479
+ delete this.data.worksheet.sheetData[0].row;
480
+ }
420
481
  }
421
- }
422
482
  }
423
- export {
424
- ExcelXmlWorksheet
425
- };
426
- //# sourceMappingURL=excel-xml-worksheet.js.map
483
+ //# sourceMappingURL=excel-xml-worksheet.js.map