@simplysm/excel 14.0.46 → 14.0.48

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.
@@ -0,0 +1,73 @@
1
+ # Wrapper
2
+
3
+ ## `ExcelWrapper`
4
+
5
+ Zod 스키마 기반 타입 안전한 Excel 읽기/쓰기 래퍼. 스키마에서 타입 정보를 추론하여 타입 안전한 읽기/쓰기를 제공한다.
6
+
7
+ ```typescript
8
+ export class ExcelWrapper<TSchema extends z.ZodObject<z.ZodRawShape>> {
9
+ constructor(schema: TSchema);
10
+
11
+ async read(
12
+ file: Bytes | Blob,
13
+ wsNameOrIndex?: string | number,
14
+ options?: { excludes?: (keyof z.infer<TSchema>)[] },
15
+ ): Promise<z.infer<TSchema>[]>;
16
+
17
+ async write(
18
+ wsName: string,
19
+ records: Partial<z.infer<TSchema>>[],
20
+ options?: { excludes?: (keyof z.infer<TSchema>)[] },
21
+ ): Promise<ExcelWorkbook>;
22
+ }
23
+ ```
24
+
25
+ ### Constructor
26
+
27
+ | Parameter | Type | Description |
28
+ |-----------|------|-------------|
29
+ | `schema` | `TSchema extends z.ZodObject<z.ZodRawShape>` | Zod 스키마. `.describe()`로 Excel 헤더 이름을 지정한다 |
30
+
31
+ ### Methods
32
+
33
+ #### `read(file, wsNameOrIndex?, options?)`
34
+
35
+ Excel 파일을 레코드 배열로 읽는다. 헤더 행의 텍스트를 스키마의 `.describe()` 값과 매칭하여 필드를 연결한다. Zod 스키마로 유효성 검사를 수행하며, 실패 시 에러를 던진다.
36
+
37
+ | Parameter | Type | Description |
38
+ |-----------|------|-------------|
39
+ | `file` | `Bytes \| Blob` | Excel 파일 데이터 |
40
+ | `wsNameOrIndex` | `string \| number` | 워크시트 이름 또는 0 기반 인덱스 (기본값: `0`) |
41
+ | `options.excludes` | `(keyof z.infer<TSchema>)[]` | 읽기에서 제외할 필드 키 배열 |
42
+
43
+ **반환값:** `z.infer<TSchema>[]` - 스키마 타입으로 추론된 레코드 배열
44
+
45
+ **타입 변환 규칙:**
46
+
47
+ | 스키마 타입 | 변환 동작 |
48
+ |------------|-----------|
49
+ | `z.string()` | 문자열로 변환 (`String(rawValue)`) |
50
+ | `z.number()` | 숫자로 파싱 (`num.parseFloat`) |
51
+ | `z.boolean()` | `"1"`, `"true"` -> `true`, `"0"`, `"false"` -> `false` |
52
+ | `z.optional()` / `z.nullable()` | 빈 셀을 `undefined`로 반환 |
53
+ | `z.default(value)` | 빈 셀에 기본값 적용 |
54
+ | `DateOnly` / `DateTime` / `Time` | `instanceof`로 직접 전달 |
55
+
56
+ #### `write(wsName, records, options?)`
57
+
58
+ 레코드 배열을 Excel 워크북으로 변환한다. 반환된 `ExcelWorkbook`의 리소스 관리는 호출자의 책임이다. 내부에서 에러 발생 시 워크북이 자동으로 `close()`된다.
59
+
60
+ | Parameter | Type | Description |
61
+ |-----------|------|-------------|
62
+ | `wsName` | `string` | 워크시트 이름 |
63
+ | `records` | `Partial<z.infer<TSchema>>[]` | 레코드 배열 |
64
+ | `options.excludes` | `(keyof z.infer<TSchema>)[]` | 쓰기에서 제외할 필드 키 배열 |
65
+
66
+ **반환값:** `ExcelWorkbook` - 호출자가 `try-finally` 블록에서 `close()`를 호출하여 리소스를 관리해야 한다
67
+
68
+ **쓰기 동작:**
69
+
70
+ - 첫 번째 행에 헤더 자동 생성 (스키마의 `.describe()` 값 사용)
71
+ - 모든 셀에 테두리 스타일 자동 적용
72
+ - 필수 비boolean 필드의 헤더에 노란색 배경(`00FFFF00`) 강조
73
+ - 확대/축소 85%, 첫 번째 행 틀 고정 자동 설정
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/excel",
3
- "version": "14.0.46",
3
+ "version": "14.0.48",
4
4
  "description": "심플리즘 패키지 - 엑셀 (neutral)",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -14,7 +14,8 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "files": [
16
16
  "dist",
17
- "src"
17
+ "src",
18
+ "docs"
18
19
  ],
19
20
  "sideEffects": false,
20
21
  "devDependencies": {
@@ -23,6 +24,6 @@
23
24
  "dependencies": {
24
25
  "mime": "^4.1.0",
25
26
  "zod": "^4.3.6",
26
- "@simplysm/core-common": "14.0.46"
27
+ "@simplysm/core-common": "14.0.48"
27
28
  }
28
29
  }
package/src/excel-cell.ts CHANGED
@@ -231,7 +231,8 @@ export class ExcelCell {
231
231
  * @param opts.border 테두리 위치 배열 (예: ["left", "right", "top", "bottom"])
232
232
  * @param opts.horizontalAlign 가로 정렬 ("left", "center", "right")
233
233
  * @param opts.verticalAlign 세로 정렬 ("top", "center", "bottom")
234
- * @param opts.numberFormat 숫자 형식 ("number", "DateOnly", "DateTime", "Time", "string")
234
+ * @param opts.numberFormat 숫자 형식 프리셋 ("number", "DateOnly", "DateTime", "Time", "string")
235
+ * @param opts.numberFormatCode 커스텀 Excel formatCode (예: "0.000000"). `numberFormat`과 동시 지정 시 이 필드가 우선한다.
235
236
  */
236
237
  async setStyle(opts: ExcelStyleOptions): Promise<void> {
237
238
  const style: ExcelStyle = {};
@@ -255,7 +256,9 @@ export class ExcelCell {
255
256
  style.verticalAlign = opts.verticalAlign;
256
257
  }
257
258
 
258
- if (opts.numberFormat != null) {
259
+ if (opts.numberFormatCode != null) {
260
+ style.numFmtCode = opts.numberFormatCode;
261
+ } else if (opts.numberFormat != null) {
259
262
  style.numFmtId = ExcelUtils.convertNumFmtNameToId(opts.numberFormat).toString();
260
263
  }
261
264
 
package/src/types.ts CHANGED
@@ -376,6 +376,9 @@ export type ExcelVerticalAlign = "center" | "top" | "bottom";
376
376
  * verticalAlign: "center",
377
377
  * numberFormat: "number",
378
378
  * });
379
+ *
380
+ * // 임의의 Excel formatCode 지정
381
+ * await cell.setStyle({ numberFormatCode: "0.000000" });
379
382
  * ```
380
383
  */
381
384
  export interface ExcelStyleOptions {
@@ -387,8 +390,13 @@ export interface ExcelStyleOptions {
387
390
  horizontalAlign?: ExcelHorizontalAlign;
388
391
  /** 세로 정렬 */
389
392
  verticalAlign?: ExcelVerticalAlign;
390
- /** 숫자 형식 */
393
+ /** 숫자 형식 프리셋 */
391
394
  numberFormat?: ExcelNumberFormat;
395
+ /**
396
+ * 커스텀 Excel formatCode 문자열 (예: "0.000000", "#,##0.00", "0.00%").
397
+ * `numberFormat`과 동시 지정 시 이 필드가 우선 적용된다.
398
+ */
399
+ numberFormatCode?: string;
392
400
  }
393
401
 
394
402
  //#endregion