@simplysm/excel 13.0.0-beta.4 → 13.0.0-beta.44

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 (163) hide show
  1. package/README.md +15 -0
  2. package/dist/excel-cell.d.ts.map +1 -0
  3. package/dist/excel-cell.js +3 -3
  4. package/dist/excel-col.d.ts.map +1 -0
  5. package/dist/excel-col.js +1 -1
  6. package/dist/excel-row.d.ts.map +1 -0
  7. package/dist/excel-row.js +1 -1
  8. package/dist/excel-workbook.d.ts.map +1 -0
  9. package/dist/excel-workbook.js +7 -7
  10. package/dist/excel-workbook.js.map +2 -2
  11. package/dist/excel-worksheet.d.ts.map +1 -0
  12. package/dist/excel-worksheet.js +4 -4
  13. package/dist/excel-wrapper.d.ts.map +1 -0
  14. package/dist/excel-wrapper.js +1 -1
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +8 -8
  17. package/dist/types.d.ts.map +1 -0
  18. package/dist/utils/excel-utils.d.ts.map +1 -0
  19. package/dist/utils/zip-cache.d.ts.map +1 -0
  20. package/dist/utils/zip-cache.js +8 -8
  21. package/dist/xml/excel-xml-content-type.d.ts.map +1 -0
  22. package/dist/xml/excel-xml-drawing.d.ts.map +1 -0
  23. package/dist/xml/excel-xml-relationship.d.ts.map +1 -0
  24. package/dist/xml/excel-xml-shared-string.d.ts.map +1 -0
  25. package/dist/xml/excel-xml-style.d.ts.map +1 -0
  26. package/dist/xml/excel-xml-unknown.d.ts.map +1 -0
  27. package/dist/xml/excel-xml-workbook.d.ts.map +1 -0
  28. package/dist/xml/excel-xml-worksheet.d.ts.map +1 -0
  29. package/dist/xml/excel-xml-worksheet.js +1 -1
  30. package/package.json +7 -4
  31. package/.cache/typecheck-browser.tsbuildinfo +0 -1
  32. package/.cache/typecheck-node.tsbuildinfo +0 -1
  33. package/.cache/typecheck-tests-browser.tsbuildinfo +0 -1
  34. package/.cache/typecheck-tests-node.tsbuildinfo +0 -1
  35. package/dist/core-common/src/common.types.d.ts +0 -74
  36. package/dist/core-common/src/common.types.d.ts.map +0 -1
  37. package/dist/core-common/src/env.d.ts +0 -6
  38. package/dist/core-common/src/env.d.ts.map +0 -1
  39. package/dist/core-common/src/errors/argument-error.d.ts +0 -25
  40. package/dist/core-common/src/errors/argument-error.d.ts.map +0 -1
  41. package/dist/core-common/src/errors/not-implemented-error.d.ts +0 -29
  42. package/dist/core-common/src/errors/not-implemented-error.d.ts.map +0 -1
  43. package/dist/core-common/src/errors/sd-error.d.ts +0 -27
  44. package/dist/core-common/src/errors/sd-error.d.ts.map +0 -1
  45. package/dist/core-common/src/errors/timeout-error.d.ts +0 -31
  46. package/dist/core-common/src/errors/timeout-error.d.ts.map +0 -1
  47. package/dist/core-common/src/extensions/arr-ext.d.ts +0 -15
  48. package/dist/core-common/src/extensions/arr-ext.d.ts.map +0 -1
  49. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts +0 -19
  50. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts.map +0 -1
  51. package/dist/core-common/src/extensions/arr-ext.types.d.ts +0 -215
  52. package/dist/core-common/src/extensions/arr-ext.types.d.ts.map +0 -1
  53. package/dist/core-common/src/extensions/map-ext.d.ts +0 -57
  54. package/dist/core-common/src/extensions/map-ext.d.ts.map +0 -1
  55. package/dist/core-common/src/extensions/set-ext.d.ts +0 -36
  56. package/dist/core-common/src/extensions/set-ext.d.ts.map +0 -1
  57. package/dist/core-common/src/features/debounce-queue.d.ts +0 -53
  58. package/dist/core-common/src/features/debounce-queue.d.ts.map +0 -1
  59. package/dist/core-common/src/features/event-emitter.d.ts +0 -66
  60. package/dist/core-common/src/features/event-emitter.d.ts.map +0 -1
  61. package/dist/core-common/src/features/serial-queue.d.ts +0 -47
  62. package/dist/core-common/src/features/serial-queue.d.ts.map +0 -1
  63. package/dist/core-common/src/index.d.ts +0 -32
  64. package/dist/core-common/src/index.d.ts.map +0 -1
  65. package/dist/core-common/src/types/date-only.d.ts +0 -152
  66. package/dist/core-common/src/types/date-only.d.ts.map +0 -1
  67. package/dist/core-common/src/types/date-time.d.ts +0 -96
  68. package/dist/core-common/src/types/date-time.d.ts.map +0 -1
  69. package/dist/core-common/src/types/lazy-gc-map.d.ts +0 -80
  70. package/dist/core-common/src/types/lazy-gc-map.d.ts.map +0 -1
  71. package/dist/core-common/src/types/time.d.ts +0 -68
  72. package/dist/core-common/src/types/time.d.ts.map +0 -1
  73. package/dist/core-common/src/types/uuid.d.ts +0 -35
  74. package/dist/core-common/src/types/uuid.d.ts.map +0 -1
  75. package/dist/core-common/src/utils/bytes.d.ts +0 -51
  76. package/dist/core-common/src/utils/bytes.d.ts.map +0 -1
  77. package/dist/core-common/src/utils/date-format.d.ts +0 -90
  78. package/dist/core-common/src/utils/date-format.d.ts.map +0 -1
  79. package/dist/core-common/src/utils/json.d.ts +0 -34
  80. package/dist/core-common/src/utils/json.d.ts.map +0 -1
  81. package/dist/core-common/src/utils/num.d.ts +0 -60
  82. package/dist/core-common/src/utils/num.d.ts.map +0 -1
  83. package/dist/core-common/src/utils/obj.d.ts +0 -258
  84. package/dist/core-common/src/utils/obj.d.ts.map +0 -1
  85. package/dist/core-common/src/utils/path.d.ts +0 -23
  86. package/dist/core-common/src/utils/path.d.ts.map +0 -1
  87. package/dist/core-common/src/utils/primitive.d.ts +0 -18
  88. package/dist/core-common/src/utils/primitive.d.ts.map +0 -1
  89. package/dist/core-common/src/utils/str.d.ts +0 -103
  90. package/dist/core-common/src/utils/str.d.ts.map +0 -1
  91. package/dist/core-common/src/utils/template-strings.d.ts +0 -84
  92. package/dist/core-common/src/utils/template-strings.d.ts.map +0 -1
  93. package/dist/core-common/src/utils/transferable.d.ts +0 -47
  94. package/dist/core-common/src/utils/transferable.d.ts.map +0 -1
  95. package/dist/core-common/src/utils/wait.d.ts +0 -19
  96. package/dist/core-common/src/utils/wait.d.ts.map +0 -1
  97. package/dist/core-common/src/utils/xml.d.ts +0 -36
  98. package/dist/core-common/src/utils/xml.d.ts.map +0 -1
  99. package/dist/core-common/src/zip/sd-zip.d.ts +0 -80
  100. package/dist/core-common/src/zip/sd-zip.d.ts.map +0 -1
  101. package/dist/excel/src/excel-cell.d.ts.map +0 -1
  102. package/dist/excel/src/excel-col.d.ts.map +0 -1
  103. package/dist/excel/src/excel-row.d.ts.map +0 -1
  104. package/dist/excel/src/excel-workbook.d.ts.map +0 -1
  105. package/dist/excel/src/excel-worksheet.d.ts.map +0 -1
  106. package/dist/excel/src/excel-wrapper.d.ts.map +0 -1
  107. package/dist/excel/src/index.d.ts.map +0 -1
  108. package/dist/excel/src/types.d.ts.map +0 -1
  109. package/dist/excel/src/utils/excel-utils.d.ts.map +0 -1
  110. package/dist/excel/src/utils/zip-cache.d.ts.map +0 -1
  111. package/dist/excel/src/xml/excel-xml-content-type.d.ts.map +0 -1
  112. package/dist/excel/src/xml/excel-xml-drawing.d.ts.map +0 -1
  113. package/dist/excel/src/xml/excel-xml-relationship.d.ts.map +0 -1
  114. package/dist/excel/src/xml/excel-xml-shared-string.d.ts.map +0 -1
  115. package/dist/excel/src/xml/excel-xml-style.d.ts.map +0 -1
  116. package/dist/excel/src/xml/excel-xml-unknown.d.ts.map +0 -1
  117. package/dist/excel/src/xml/excel-xml-workbook.d.ts.map +0 -1
  118. package/dist/excel/src/xml/excel-xml-worksheet.d.ts.map +0 -1
  119. package/src/excel-cell.ts +0 -326
  120. package/src/excel-col.ts +0 -43
  121. package/src/excel-row.ts +0 -37
  122. package/src/excel-workbook.ts +0 -206
  123. package/src/excel-worksheet.ts +0 -380
  124. package/src/excel-wrapper.ts +0 -219
  125. package/src/index.ts +0 -13
  126. package/src/types.ts +0 -396
  127. package/src/utils/excel-utils.ts +0 -201
  128. package/src/utils/zip-cache.ts +0 -103
  129. package/src/xml/excel-xml-content-type.ts +0 -64
  130. package/src/xml/excel-xml-drawing.ts +0 -87
  131. package/src/xml/excel-xml-relationship.ts +0 -86
  132. package/src/xml/excel-xml-shared-string.ts +0 -80
  133. package/src/xml/excel-xml-style.ts +0 -393
  134. package/src/xml/excel-xml-unknown.ts +0 -11
  135. package/src/xml/excel-xml-workbook.ts +0 -112
  136. package/src/xml/excel-xml-worksheet.ts +0 -544
  137. package/tests/excel-cell.spec.ts +0 -407
  138. package/tests/excel-col.spec.ts +0 -112
  139. package/tests/excel-row.spec.ts +0 -71
  140. package/tests/excel-workbook.spec.ts +0 -166
  141. package/tests/excel-worksheet.spec.ts +0 -389
  142. package/tests/excel-wrapper.spec.ts +0 -275
  143. package/tests/fixtures/logo.png +0 -0
  144. package/tests/image-insert.spec.ts +0 -188
  145. package/tests/utils/excel-utils.spec.ts +0 -240
  146. /package/dist/{excel/src/excel-cell.d.ts → excel-cell.d.ts} +0 -0
  147. /package/dist/{excel/src/excel-col.d.ts → excel-col.d.ts} +0 -0
  148. /package/dist/{excel/src/excel-row.d.ts → excel-row.d.ts} +0 -0
  149. /package/dist/{excel/src/excel-workbook.d.ts → excel-workbook.d.ts} +0 -0
  150. /package/dist/{excel/src/excel-worksheet.d.ts → excel-worksheet.d.ts} +0 -0
  151. /package/dist/{excel/src/excel-wrapper.d.ts → excel-wrapper.d.ts} +0 -0
  152. /package/dist/{excel/src/index.d.ts → index.d.ts} +0 -0
  153. /package/dist/{excel/src/types.d.ts → types.d.ts} +0 -0
  154. /package/dist/{excel/src/utils → utils}/excel-utils.d.ts +0 -0
  155. /package/dist/{excel/src/utils → utils}/zip-cache.d.ts +0 -0
  156. /package/dist/{excel/src/xml → xml}/excel-xml-content-type.d.ts +0 -0
  157. /package/dist/{excel/src/xml → xml}/excel-xml-drawing.d.ts +0 -0
  158. /package/dist/{excel/src/xml → xml}/excel-xml-relationship.d.ts +0 -0
  159. /package/dist/{excel/src/xml → xml}/excel-xml-shared-string.d.ts +0 -0
  160. /package/dist/{excel/src/xml → xml}/excel-xml-style.d.ts +0 -0
  161. /package/dist/{excel/src/xml → xml}/excel-xml-unknown.d.ts +0 -0
  162. /package/dist/{excel/src/xml → xml}/excel-xml-workbook.d.ts +0 -0
  163. /package/dist/{excel/src/xml → xml}/excel-xml-worksheet.d.ts +0 -0
@@ -1,393 +0,0 @@
1
- import type {
2
- ExcelBorderPosition,
3
- ExcelHorizontalAlign,
4
- ExcelVerticalAlign,
5
- ExcelXml,
6
- ExcelXmlStyleData,
7
- ExcelXmlStyleDataBorder,
8
- ExcelXmlStyleDataFill,
9
- ExcelXmlStyleDataXf,
10
- } from "../types";
11
- import "@simplysm/core-common";
12
- import { numParseInt, objClone, objEqual } from "@simplysm/core-common";
13
-
14
- export interface ExcelStyle {
15
- numFmtId?: string;
16
- numFmtCode?: string;
17
- border?: ExcelBorderPosition[];
18
- background?: string;
19
- verticalAlign?: ExcelVerticalAlign;
20
- horizontalAlign?: ExcelHorizontalAlign;
21
- }
22
-
23
- /**
24
- * xl/styles.xml 파일을 관리하는 클래스.
25
- * 숫자 형식, 배경색, 테두리, 정렬 등의 스타일을 처리한다.
26
- */
27
- export class ExcelXmlStyle implements ExcelXml {
28
- data: ExcelXmlStyleData;
29
-
30
- constructor(data?: ExcelXmlStyleData) {
31
- if (data === undefined) {
32
- this.data = {
33
- styleSheet: {
34
- $: {
35
- xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
36
- },
37
- fonts: [
38
- {
39
- $: { count: "1" },
40
- font: [{}],
41
- },
42
- ],
43
- fills: [
44
- {
45
- $: { count: "2" },
46
- fill: [
47
- { patternFill: [{ $: { patternType: "none" } }] },
48
- { patternFill: [{ $: { patternType: "gray125" } }] },
49
- ],
50
- },
51
- ],
52
- borders: [
53
- {
54
- $: { count: "1" },
55
- border: [{}],
56
- },
57
- ],
58
- cellXfs: [
59
- {
60
- $: { count: "1" },
61
- xf: [{ $: { numFmtId: "0" } }],
62
- },
63
- ],
64
- },
65
- };
66
- } else {
67
- this.data = data;
68
- }
69
- }
70
-
71
- add(style: ExcelStyle): string {
72
- const newXf: ExcelXmlStyleDataXf = { $: {} };
73
-
74
- if (style.numFmtId !== undefined) {
75
- newXf.$.numFmtId = style.numFmtId;
76
- }
77
-
78
- if (style.numFmtCode !== undefined) {
79
- newXf.$.numFmtId = this._setNumFmtCode(style.numFmtCode);
80
- newXf.$.applyNumberFormat = "1";
81
- }
82
-
83
- if (style.background !== undefined) {
84
- const newFill: ExcelXmlStyleDataFill = {
85
- patternFill: [
86
- {
87
- $: { patternType: "solid" },
88
- fgColor: [{ $: { rgb: style.background.toUpperCase() } }],
89
- },
90
- ],
91
- };
92
-
93
- newXf.$.applyFill = "1";
94
- newXf.$.fillId = this._getSameOrCreateFill(newFill);
95
- }
96
-
97
- if (style.border !== undefined) {
98
- const newBorder = this._createBorderFromPositions(style.border);
99
- newXf.$.applyBorder = "1";
100
- newXf.$.borderId = this._getSameOrCreateBorder(newBorder);
101
- }
102
-
103
- this._applyAlignment(newXf, style);
104
-
105
- return this._getSameOrCreateXf(newXf);
106
- }
107
-
108
- addWithClone(id: string, style: ExcelStyle): string {
109
- const idNum = numParseInt(id);
110
- if (idNum == null) {
111
- throw new Error(`잘못된 스타일 ID: ${id}`);
112
- }
113
- const xfArray = this.data.styleSheet.cellXfs[0].xf;
114
- if (idNum < 0 || idNum >= xfArray.length) {
115
- throw new Error(`존재하지 않는 스타일 ID: ${id} (범위: 0-${xfArray.length - 1})`);
116
- }
117
- const prevXf = xfArray[idNum];
118
- const cloneXf = objClone(prevXf);
119
-
120
- if (style.numFmtId !== undefined) {
121
- cloneXf.$.numFmtId = style.numFmtId;
122
- }
123
-
124
- if (style.numFmtCode !== undefined) {
125
- cloneXf.$.numFmtId = this._setNumFmtCode(style.numFmtCode);
126
- cloneXf.$.applyNumberFormat = "1";
127
- }
128
-
129
- if (style.background !== undefined) {
130
- const fillIdNum = cloneXf.$.fillId !== undefined ? numParseInt(cloneXf.$.fillId) : undefined;
131
- const prevFill = fillIdNum !== undefined ? this.data.styleSheet.fills[0].fill[fillIdNum] : undefined;
132
-
133
- if (prevFill != null) {
134
- const cloneFill = objClone(prevFill);
135
- cloneFill.patternFill[0].$.patternType = "solid";
136
-
137
- if (cloneFill.patternFill[0].fgColor == null) {
138
- cloneFill.patternFill[0].fgColor = [{ $: { rgb: style.background } }];
139
- } else {
140
- cloneFill.patternFill[0].fgColor[0].$.rgb = style.background;
141
- }
142
-
143
- cloneXf.$.applyFill = "1";
144
- cloneXf.$.fillId = this._getSameOrCreateFill(cloneFill);
145
- } else {
146
- const newFill: ExcelXmlStyleDataFill = {
147
- patternFill: [
148
- {
149
- $: { patternType: "solid" },
150
- fgColor: [{ $: { rgb: style.background.toUpperCase() } }],
151
- },
152
- ],
153
- };
154
- cloneXf.$.applyFill = "1";
155
- cloneXf.$.fillId = this._getSameOrCreateFill(newFill);
156
- }
157
- }
158
-
159
- if (style.border !== undefined) {
160
- const borderIdNum = cloneXf.$.borderId !== undefined ? numParseInt(cloneXf.$.borderId) : undefined;
161
- const prevBorder = borderIdNum !== undefined ? this.data.styleSheet.borders[0].border[borderIdNum] : undefined;
162
-
163
- if (prevBorder != null) {
164
- const cloneBorder = objClone(prevBorder);
165
- this._applyBorderPosition(cloneBorder, "left", style.border.includes("left"));
166
- this._applyBorderPosition(cloneBorder, "right", style.border.includes("right"));
167
- this._applyBorderPosition(cloneBorder, "top", style.border.includes("top"));
168
- this._applyBorderPosition(cloneBorder, "bottom", style.border.includes("bottom"));
169
-
170
- cloneXf.$.applyBorder = "1";
171
- cloneXf.$.borderId = this._getSameOrCreateBorder(cloneBorder);
172
- } else {
173
- const newBorder = this._createBorderFromPositions(style.border);
174
- cloneXf.$.applyBorder = "1";
175
- cloneXf.$.borderId = this._getSameOrCreateBorder(newBorder);
176
- }
177
- }
178
-
179
- this._applyAlignment(cloneXf, style);
180
-
181
- return this._getSameOrCreateXf(cloneXf);
182
- }
183
-
184
- get(id: string): ExcelStyle {
185
- const idNum = numParseInt(id);
186
- if (idNum == null) {
187
- throw new Error(`잘못된 스타일 ID: ${id}`);
188
- }
189
- const xf = this.data.styleSheet.cellXfs[0].xf[idNum] as ExcelXmlStyleDataXf | undefined;
190
-
191
- const result: ExcelStyle = {};
192
-
193
- if (xf !== undefined) {
194
- result.numFmtId = xf.$.numFmtId;
195
-
196
- if (xf.$.fillId !== undefined) {
197
- const fillIdNum = numParseInt(xf.$.fillId);
198
- if (fillIdNum != null) {
199
- const fill = this.data.styleSheet.fills[0].fill[fillIdNum] as ExcelXmlStyleDataFill | undefined;
200
- if (fill == null) {
201
- throw new Error(
202
- `존재하지 않는 fill ID: ${xf.$.fillId} (범위: 0-${this.data.styleSheet.fills[0].fill.length - 1})`,
203
- );
204
- }
205
- result.background = fill.patternFill[0].fgColor?.[0].$.rgb;
206
- }
207
- }
208
-
209
- if (xf.$.borderId !== undefined) {
210
- const borderIdNum = numParseInt(xf.$.borderId);
211
- if (borderIdNum == null) {
212
- throw new Error(`잘못된 border ID: ${xf.$.borderId}`);
213
- }
214
- const border = this.data.styleSheet.borders[0].border[borderIdNum] as ExcelXmlStyleDataBorder | undefined;
215
- if (border == null) {
216
- throw new Error(
217
- `존재하지 않는 border ID: ${xf.$.borderId} (범위: 0-${this.data.styleSheet.borders[0].border.length - 1})`,
218
- );
219
- }
220
- if (border.top != null || border.left != null || border.right != null || border.bottom != null) {
221
- result.border = [];
222
- if (border.left != null) {
223
- result.border.push("left");
224
- }
225
- if (border.right != null) {
226
- result.border.push("right");
227
- }
228
- if (border.top != null) {
229
- result.border.push("top");
230
- }
231
- if (border.bottom != null) {
232
- result.border.push("bottom");
233
- }
234
- }
235
- }
236
-
237
- result.verticalAlign = xf.alignment?.[0].$.vertical;
238
- result.horizontalAlign = xf.alignment?.[0].$.horizontal;
239
- }
240
-
241
- return result;
242
- }
243
-
244
- getNumFmtCode(numFmtId: string): string | undefined {
245
- return (this.data.styleSheet.numFmts?.[0].numFmt ?? []).single((item) => item.$.numFmtId === numFmtId)?.$
246
- .formatCode;
247
- }
248
-
249
- cleanup(): void {
250
- const result = {} as ExcelXmlStyleData["styleSheet"];
251
-
252
- // 순서 정렬 (numFmts 맨위로)
253
-
254
- if (this.data.styleSheet.numFmts != null) {
255
- result.numFmts = this.data.styleSheet.numFmts;
256
- }
257
-
258
- const styleSheetRec = this.data.styleSheet as Record<string, unknown>;
259
- const resultRec = result as Record<string, unknown>;
260
- for (const key of Object.keys(styleSheetRec)) {
261
- if (key === "numFmts") continue;
262
-
263
- resultRec[key] = styleSheetRec[key];
264
- }
265
-
266
- this.data.styleSheet = result;
267
- }
268
-
269
- //#region Private Methods
270
-
271
- private _setNumFmtCode(numFmtCode: string): string {
272
- // 이미 해당 code가 있으면 넘기기
273
- const existsNumFmtId = (this.data.styleSheet.numFmts?.[0].numFmt ?? []).single(
274
- (item) => item.$.formatCode === numFmtCode,
275
- )?.$.numFmtId;
276
- if (existsNumFmtId != null) {
277
- return existsNumFmtId;
278
- }
279
-
280
- this.data.styleSheet.numFmts = this.data.styleSheet.numFmts ?? [
281
- {
282
- $: { count: "0" },
283
- numFmt: [],
284
- },
285
- ];
286
-
287
- this.data.styleSheet.numFmts[0].numFmt = this.data.styleSheet.numFmts[0].numFmt ?? [];
288
-
289
- // Excel 사용자 정의 숫자 형식은 ID 180 이상부터 시작한다 (0-163: 내장 형식, 164-179: 예약됨)
290
- const numFmts = this.data.styleSheet.numFmts[0].numFmt;
291
- const maxItem =
292
- numFmts.length > 0 ? numFmts.orderByDesc((item) => numParseInt(item.$.numFmtId) ?? 180).first() : undefined;
293
- const maxId = maxItem ? (numParseInt(maxItem.$.numFmtId) ?? 180) : 180;
294
- const nextNumFmtId = (maxId + 1).toString();
295
- this.data.styleSheet.numFmts[0].numFmt.push({
296
- $: {
297
- numFmtId: nextNumFmtId,
298
- formatCode: numFmtCode,
299
- },
300
- });
301
- this.data.styleSheet.numFmts[0].$.count = (
302
- (numParseInt(this.data.styleSheet.numFmts[0].$.count) ?? 0) + 1
303
- ).toString();
304
-
305
- return nextNumFmtId;
306
- }
307
-
308
- private _applyAlignment(xf: ExcelXmlStyleDataXf, style: ExcelStyle): void {
309
- if (style.verticalAlign !== undefined) {
310
- xf.$.applyAlignment = "1";
311
- if (xf.alignment == null) {
312
- xf.alignment = [{ $: { vertical: style.verticalAlign } }];
313
- } else {
314
- xf.alignment[0].$.vertical = style.verticalAlign;
315
- }
316
- }
317
-
318
- if (style.horizontalAlign !== undefined) {
319
- xf.$.applyAlignment = "1";
320
- if (xf.alignment == null) {
321
- xf.alignment = [{ $: { horizontal: style.horizontalAlign } }];
322
- } else {
323
- xf.alignment[0].$.horizontal = style.horizontalAlign;
324
- }
325
- }
326
- }
327
-
328
- private _createBorderFromPositions(positions: ExcelBorderPosition[]): ExcelXmlStyleDataBorder {
329
- return {
330
- ...(positions.includes("left") ? { left: [{ $: { style: "thin" }, color: [{ $: { rgb: "00000000" } }] }] } : {}),
331
- ...(positions.includes("right")
332
- ? { right: [{ $: { style: "thin" }, color: [{ $: { rgb: "00000000" } }] }] }
333
- : {}),
334
- ...(positions.includes("top") ? { top: [{ $: { style: "thin" }, color: [{ $: { rgb: "00000000" } }] }] } : {}),
335
- ...(positions.includes("bottom")
336
- ? { bottom: [{ $: { style: "thin" }, color: [{ $: { rgb: "00000000" } }] }] }
337
- : {}),
338
- };
339
- }
340
-
341
- private _applyBorderPosition(border: ExcelXmlStyleDataBorder, position: ExcelBorderPosition, enabled: boolean): void {
342
- if (enabled) {
343
- const existing = border[position];
344
- if (existing == null) {
345
- border[position] = [{ $: { style: "thin" }, color: [{ $: { rgb: "00000000" } }] }];
346
- } else if (existing[0].color == null) {
347
- existing[0].color = [{ $: { rgb: "00000000" } }];
348
- } else {
349
- existing[0].color[0].$.rgb = "00000000";
350
- }
351
- } else {
352
- delete border[position];
353
- }
354
- }
355
-
356
- private _getSameOrCreateXf(xfItem: ExcelXmlStyleDataXf): string {
357
- const prevSameXf = this.data.styleSheet.cellXfs[0].xf.single((item) => objEqual(item, xfItem));
358
-
359
- if (prevSameXf != null) {
360
- return this.data.styleSheet.cellXfs[0].xf.indexOf(prevSameXf).toString();
361
- } else {
362
- this.data.styleSheet.cellXfs[0].xf.push(xfItem);
363
- this.data.styleSheet.cellXfs[0].$.count = this.data.styleSheet.cellXfs[0].xf.length.toString();
364
- return (this.data.styleSheet.cellXfs[0].xf.length - 1).toString();
365
- }
366
- }
367
-
368
- private _getSameOrCreateFill(fillItem: ExcelXmlStyleDataFill): string {
369
- const prevSameFill = this.data.styleSheet.fills[0].fill.single((item) => objEqual(item, fillItem));
370
-
371
- if (prevSameFill != null) {
372
- return this.data.styleSheet.fills[0].fill.indexOf(prevSameFill).toString();
373
- } else {
374
- this.data.styleSheet.fills[0].fill.push(fillItem);
375
- this.data.styleSheet.fills[0].$.count = this.data.styleSheet.fills[0].fill.length.toString();
376
- return (this.data.styleSheet.fills[0].fill.length - 1).toString();
377
- }
378
- }
379
-
380
- private _getSameOrCreateBorder(borderItem: ExcelXmlStyleDataBorder): string {
381
- const prevSameBorder = this.data.styleSheet.borders[0].border.single((item) => objEqual(item, borderItem));
382
-
383
- if (prevSameBorder != null) {
384
- return this.data.styleSheet.borders[0].border.indexOf(prevSameBorder).toString();
385
- } else {
386
- this.data.styleSheet.borders[0].border.push(borderItem);
387
- this.data.styleSheet.borders[0].$.count = this.data.styleSheet.borders[0].border.length.toString();
388
- return (this.data.styleSheet.borders[0].border.length - 1).toString();
389
- }
390
- }
391
-
392
- //#endregion
393
- }
@@ -1,11 +0,0 @@
1
- import type { ExcelXml } from "../types";
2
-
3
- /**
4
- * 알 수 없는 형식의 Excel XML 데이터를 보존하는 클래스.
5
- * 원본 데이터를 손실 없이 유지한다.
6
- */
7
- export class ExcelXmlUnknown implements ExcelXml {
8
- constructor(public readonly data: Record<string, unknown>) {}
9
-
10
- cleanup(): void {}
11
- }
@@ -1,112 +0,0 @@
1
- import "@simplysm/core-common";
2
- import { numParseInt } from "@simplysm/core-common";
3
- import type { ExcelXml, ExcelXmlWorkbookData } from "../types";
4
-
5
- /**
6
- * xl/workbook.xml 파일을 관리하는 클래스.
7
- * 워크시트 목록과 관계 ID를 처리한다.
8
- */
9
- export class ExcelXmlWorkbook implements ExcelXml {
10
- data: ExcelXmlWorkbookData;
11
-
12
- constructor(data?: ExcelXmlWorkbookData) {
13
- if (data === undefined) {
14
- this.data = {
15
- workbook: {
16
- $: {
17
- "xmlns": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
18
- "xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
19
- },
20
- },
21
- };
22
- } else {
23
- this.data = data;
24
- }
25
- }
26
-
27
- get lastWsRelId(): number | undefined {
28
- const sheets = this.data.workbook.sheets?.[0].sheet;
29
- if (!sheets || sheets.length === 0) return undefined;
30
- const maxSheet = sheets.orderByDesc((sheet) => numParseInt(sheet.$["r:id"])!).first();
31
- return maxSheet ? numParseInt(maxSheet.$["r:id"]) : undefined;
32
- }
33
-
34
- get sheetNames(): string[] {
35
- return this.data.workbook.sheets?.[0].sheet.map((item) => item.$.name) ?? [];
36
- }
37
-
38
- addWorksheet(name: string): this {
39
- const replacedName = this._getReplacedName(name);
40
-
41
- const newWsRelId = (this.lastWsRelId ?? 0) + 1;
42
-
43
- this.data.workbook.sheets = this.data.workbook.sheets ?? [{ sheet: [] }];
44
- this.data.workbook.sheets[0].sheet.push({
45
- $: {
46
- "name": replacedName,
47
- "sheetId": newWsRelId.toString(),
48
- "r:id": `rId${newWsRelId}`,
49
- },
50
- });
51
-
52
- return this;
53
- }
54
-
55
- cleanup(): void {
56
- const result = {} as ExcelXmlWorkbookData["workbook"];
57
-
58
- // 순서 정렬 ("sheets"기준 앞뒤로, 나머지는 원래위치대로)
59
-
60
- const workbookRec = this.data.workbook as Record<string, unknown>;
61
- const resultRec = result as Record<string, unknown>;
62
-
63
- for (const key of Object.keys(this.data.workbook)) {
64
- if (key === "bookViews") continue;
65
-
66
- if (key === "sheets") {
67
- if (this.data.workbook.bookViews != null) {
68
- result.bookViews = this.data.workbook.bookViews;
69
- }
70
- result.sheets = this.data.workbook.sheets;
71
- } else {
72
- resultRec[key] = workbookRec[key];
73
- }
74
- }
75
-
76
- this.data.workbook = result;
77
- }
78
-
79
- initializeView(): void {
80
- this.data.workbook.bookViews = this.data.workbook.bookViews ?? [{ workbookView: [{}] }];
81
- }
82
-
83
- getWsRelIdByName(name: string): number | undefined {
84
- return numParseInt((this.data.workbook.sheets?.[0].sheet ?? []).single((item) => item.$.name === name)?.$["r:id"]);
85
- }
86
-
87
- getWsRelIdByIndex(index: number): number | undefined {
88
- return numParseInt(this.data.workbook.sheets?.[0].sheet[index]?.$["r:id"]);
89
- }
90
-
91
- getWorksheetNameById(id: number): string | undefined {
92
- return this._getSheetDataById(id)?.$.name;
93
- }
94
-
95
- setWorksheetNameById(id: number, newName: string): void {
96
- const sheetData = this._getSheetDataById(id);
97
- if (sheetData == null) {
98
- throw new Error(`워크시트 ID ${id}를 찾을 수 없습니다`);
99
- }
100
- const replacedName = this._getReplacedName(newName);
101
- sheetData.$.name = replacedName;
102
- }
103
-
104
- private _getSheetDataById(id: number) {
105
- return (this.data.workbook.sheets?.[0].sheet ?? []).single((item) => numParseInt(item.$["r:id"]) === id);
106
- }
107
-
108
- private _getReplacedName(name: string): string {
109
- //-- 시트명칭 사용불가 텍스트를 "_"로 변환
110
- return name.replace(/[:\\/?*\[\]']/g, "_");
111
- }
112
- }