@simplysm/core-common 13.0.85 → 13.0.87

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.
package/docs/types.md CHANGED
@@ -1,242 +1,341 @@
1
- # Types
2
-
3
- Immutable date/time classes, UUID, auto-expiring map, and shared type aliases.
1
+ # 타입
4
2
 
5
3
  ## DateTime
6
4
 
5
+ 불변(immutable) 날짜/시간 타입. 모든 변경 메서드는 새 인스턴스를 반환한다.
6
+
7
+ ### 생성
8
+
9
+ ```typescript
10
+ import { DateTime } from "@simplysm/core-common";
11
+
12
+ new DateTime(); // 현재 시각
13
+ new DateTime(2024, 1, 15); // 2024-01-15 00:00:00
14
+ new DateTime(2024, 1, 15, 14, 30, 0); // 2024-01-15 14:30:00
15
+ new DateTime(2024, 1, 15, 14, 30, 0, 500); // 밀리초 포함
16
+ new DateTime(tick); // tick(밀리초)으로 생성
17
+ new DateTime(new Date()); // Date 객체에서 생성
18
+ ```
19
+
20
+ ### 파싱
21
+
7
22
  ```typescript
8
- class DateTime {
9
- constructor();
10
- constructor(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millisecond?: number);
11
- constructor(tick: number);
12
- constructor(date: Date);
13
-
14
- static parse(str: string): DateTime;
15
-
16
- readonly date: Date;
17
-
18
- get year(): number;
19
- get month(): number;
20
- get day(): number;
21
- get hour(): number;
22
- get minute(): number;
23
- get second(): number;
24
- get millisecond(): number;
25
- get tick(): number;
26
- get dayOfWeek(): number;
27
- get timezoneOffsetMinutes(): number;
28
- get isValid(): boolean;
29
-
30
- setYear(year: number): DateTime;
31
- setMonth(month: number): DateTime;
32
- setDay(day: number): DateTime;
33
- setHour(hour: number): DateTime;
34
- setMinute(minute: number): DateTime;
35
- setSecond(second: number): DateTime;
36
- setMillisecond(millisecond: number): DateTime;
37
-
38
- addYears(years: number): DateTime;
39
- addMonths(months: number): DateTime;
40
- addDays(days: number): DateTime;
41
- addHours(hours: number): DateTime;
42
- addMinutes(minutes: number): DateTime;
43
- addSeconds(seconds: number): DateTime;
44
- addMilliseconds(milliseconds: number): DateTime;
45
-
46
- toFormatString(formatStr: string): string;
47
- toString(): string; // "yyyy-MM-ddTHH:mm:ss.fffzzz"
48
- }
23
+ DateTime.parse("2024-01-15T14:30:00.000Z"); // ISO 8601
24
+ DateTime.parse("2024-01-15 14:30:00"); // yyyy-MM-dd HH:mm:ss
25
+ DateTime.parse("2024-01-15 14:30:00.123"); // yyyy-MM-dd HH:mm:ss.fff
26
+ DateTime.parse("20240115143000"); // yyyyMMddHHmmss
27
+ DateTime.parse("2024-01-15 AM 10:30:00"); // yyyy-MM-dd AM/PM HH:mm:ss
28
+ DateTime.parse("2024-01-15 오전 10:30:00"); // yyyy-MM-dd 오전/오후 HH:mm:ss
49
29
  ```
50
30
 
51
- Immutable DateTime class wrapping JavaScript `Date`. Supports millisecond precision with local timezone. All setter and add methods return a new instance.
31
+ ### 속성
32
+
33
+ | 속성 | 타입 | 설명 |
34
+ |------|------|------|
35
+ | `year` | `number` | 연도 |
36
+ | `month` | `number` | 월 (1~12) |
37
+ | `day` | `number` | 일 |
38
+ | `hour` | `number` | 시 (0~23) |
39
+ | `minute` | `number` | 분 |
40
+ | `second` | `number` | 초 |
41
+ | `millisecond` | `number` | 밀리초 |
42
+ | `tick` | `number` | epoch 밀리초 |
43
+ | `dayOfWeek` | `number` | 요일 (0=일요일) |
44
+ | `timezoneOffsetMinutes` | `number` | 타임존 오프셋(분) |
45
+ | `isValid` | `boolean` | 유효성 |
46
+ | `date` | `Date` | 내부 Date 객체 (readonly) |
47
+
48
+ ### 변경 (새 인스턴스 반환)
49
+
50
+ ```typescript
51
+ const dt = new DateTime(2024, 1, 15, 14, 30, 0);
52
+
53
+ dt.setYear(2025); // 2025-01-15 14:30:00
54
+ dt.setMonth(6); // 2024-06-15 14:30:00
55
+ dt.setDay(20); // 2024-01-20 14:30:00
56
+ dt.setHour(10); // 2024-01-15 10:30:00
57
+ dt.setMinute(45); // 2024-01-15 14:45:00
58
+ dt.setSecond(30); // 2024-01-15 14:30:30
59
+ dt.setMillisecond(500); // 2024-01-15 14:30:00.500
60
+
61
+ dt.addYears(1); // 2025-01-15 14:30:00
62
+ dt.addMonths(3); // 2024-04-15 14:30:00
63
+ dt.addDays(10); // 2024-01-25 14:30:00
64
+ dt.addHours(-2); // 2024-01-15 12:30:00
65
+ dt.addMinutes(15); // 2024-01-15 14:45:00
66
+ dt.addSeconds(30); // 2024-01-15 14:30:30
67
+ dt.addMilliseconds(500); // 2024-01-15 14:30:00.500
68
+ ```
69
+
70
+ ### 포맷
71
+
72
+ ```typescript
73
+ dt.toFormatString("yyyy-MM-dd HH:mm:ss"); // "2024-01-15 14:30:00"
74
+ dt.toFormatString("yy/M/d tt h:mm"); // "24/1/15 PM 2:30"
75
+ dt.toString(); // ISO 8601 형식 "2024-01-15T14:30:00.000+09:00"
76
+ ```
52
77
 
53
- **Parsing formats:** `yyyy-MM-dd HH:mm:ss`, `yyyy-MM-dd HH:mm:ss.fff`, `yyyyMMddHHmmss`, `yyyy-MM-dd AM/PM HH:mm:ss`, ISO 8601.
78
+ 포맷 패턴:
79
+
80
+ | 패턴 | 설명 | 예시 |
81
+ |------|------|------|
82
+ | `yyyy` | 4자리 연도 | 2024 |
83
+ | `yy` | 2자리 연도 | 24 |
84
+ | `MM` | 0패딩 월 | 01~12 |
85
+ | `M` | 월 | 1~12 |
86
+ | `ddd` | 요일 | 일, 월, 화, 수, 목, 금, 토 |
87
+ | `dd` | 0패딩 일 | 01~31 |
88
+ | `d` | 일 | 1~31 |
89
+ | `tt` | 오전/오후 | AM, PM |
90
+ | `hh` | 0패딩 12시간 | 01~12 |
91
+ | `h` | 12시간 | 1~12 |
92
+ | `HH` | 0패딩 24시간 | 00~23 |
93
+ | `H` | 24시간 | 0~23 |
94
+ | `mm` | 0패딩 분 | 00~59 |
95
+ | `m` | 분 | 0~59 |
96
+ | `ss` | 0패딩 초 | 00~59 |
97
+ | `s` | 초 | 0~59 |
98
+ | `fff` | 밀리초(3자리) | 000~999 |
99
+ | `ff` | 밀리초(2자리) | 00~99 |
100
+ | `f` | 밀리초(1자리) | 0~9 |
101
+ | `zzz` | 타임존(+-HH:mm) | +09:00 |
102
+ | `zz` | 타임존(+-HH) | +09 |
103
+ | `z` | 타임존(+-H) | +9 |
54
104
 
55
105
  ---
56
106
 
57
107
  ## DateOnly
58
108
 
109
+ 불변 날짜 전용 타입 (시간 정보 없음).
110
+
111
+ ### 생성/파싱
112
+
59
113
  ```typescript
60
- class DateOnly {
61
- constructor();
62
- constructor(year: number, month: number, day: number);
63
- constructor(tick: number);
64
- constructor(date: Date);
65
-
66
- static parse(str: string): DateOnly;
67
- static getDateByYearWeekSeq(
68
- arg: { year: number; month?: number; weekSeq: number },
69
- weekStartDay?: number,
70
- minDaysInFirstWeek?: number,
71
- ): DateOnly;
72
-
73
- readonly date: Date;
74
-
75
- get year(): number;
76
- get month(): number;
77
- get day(): number;
78
- get tick(): number;
79
- get dayOfWeek(): number;
80
- get isValid(): boolean;
81
-
82
- setYear(year: number): DateOnly;
83
- setMonth(month: number): DateOnly;
84
- setDay(day: number): DateOnly;
85
-
86
- addYears(years: number): DateOnly;
87
- addMonths(months: number): DateOnly;
88
- addDays(days: number): DateOnly;
89
-
90
- getBaseYearMonthSeqForWeekSeq(weekStartDay?: number, minDaysInFirstWeek?: number): { year: number; monthSeq: number };
91
- getWeekSeqStartDate(weekStartDay?: number, minDaysInFirstWeek?: number): DateOnly;
92
- getWeekSeqOfYear(weekStartDay?: number, minDaysInFirstWeek?: number): { year: number; weekSeq: number };
93
- getWeekSeqOfMonth(weekStartDay?: number, minDaysInFirstWeek?: number): { year: number; monthSeq: number; weekSeq: number };
94
-
95
- toFormatString(formatStr: string): string;
96
- toString(): string; // "yyyy-MM-dd"
97
- }
114
+ import { DateOnly } from "@simplysm/core-common";
115
+
116
+ new DateOnly(); // 오늘
117
+ new DateOnly(2024, 1, 15); // 2024-01-15
118
+ new DateOnly(tick); // tick(밀리초)으로 생성
119
+ new DateOnly(new Date()); // Date 객체에서 생성
120
+ DateOnly.parse("2024-01-15"); // yyyy-MM-dd
121
+ DateOnly.parse("20240115"); // yyyyMMdd
122
+ DateOnly.parse("2024-01-15T00:00:00Z"); // ISO 8601 (UTC -> 로컬 변환)
98
123
  ```
99
124
 
100
- Immutable date-only class (no time). Includes ISO 8601 week calculation utilities.
125
+ ### 속성
101
126
 
102
- **Parsing formats:** `yyyy-MM-dd`, `yyyyMMdd`, ISO 8601.
127
+ | 속성 | 타입 | 설명 |
128
+ |------|------|------|
129
+ | `year` | `number` | 연도 |
130
+ | `month` | `number` | 월 (1~12) |
131
+ | `day` | `number` | 일 |
132
+ | `tick` | `number` | epoch 밀리초 |
133
+ | `dayOfWeek` | `number` | 요일 (0=일요일) |
134
+ | `isValid` | `boolean` | 유효성 |
135
+ | `date` | `Date` | 내부 Date 객체 (readonly) |
103
136
 
104
- ---
137
+ ### 주차 계산
105
138
 
106
- ## Time
139
+ 모든 주차 메서드는 `weekStartDay`(주 시작 요일, 기본값 1=월요일)와 `minDaysInFirstWeek`(첫 주 최소 일수, 기본값 4=ISO 8601) 옵션을 지원한다.
107
140
 
108
141
  ```typescript
109
- class Time {
110
- constructor();
111
- constructor(hour: number, minute: number, second?: number, millisecond?: number);
112
- constructor(tick: number);
113
- constructor(date: Date);
114
-
115
- static parse(str: string): Time;
116
-
117
- get hour(): number;
118
- get minute(): number;
119
- get second(): number;
120
- get millisecond(): number;
121
- get tick(): number;
122
- get isValid(): boolean;
123
-
124
- setHour(hour: number): Time;
125
- setMinute(minute: number): Time;
126
- setSecond(second: number): Time;
127
- setMillisecond(millisecond: number): Time;
128
-
129
- addHours(hours: number): Time;
130
- addMinutes(minutes: number): Time;
131
- addSeconds(seconds: number): Time;
132
- addMilliseconds(milliseconds: number): Time;
133
-
134
- toFormatString(formatStr: string): string;
135
- toString(): string; // "HH:mm:ss.fff"
136
- }
142
+ const date = new DateOnly(2024, 1, 15);
143
+
144
+ // 연간 주차
145
+ date.getWeekSeqOfYear();
146
+ // { year: 2024, weekSeq: 3 }
147
+
148
+ // 월간 주차
149
+ date.getWeekSeqOfMonth();
150
+ // { year: 2024, monthSeq: 1, weekSeq: 3 }
151
+
152
+ // 해당 주의 시작일
153
+ date.getWeekSeqStartDate();
154
+
155
+ // 주차 기준 기본 연/월
156
+ date.getBaseYearMonthSeqForWeekSeq();
157
+ // { year: 2024, monthSeq: 1 }
158
+
159
+ // 연/주차로 날짜 계산
160
+ DateOnly.getDateByYearWeekSeq({ year: 2024, weekSeq: 3 });
161
+ // 2024년 3주차 시작일 (월요일)
162
+
163
+ // 월/주차로 날짜 계산
164
+ DateOnly.getDateByYearWeekSeq({ year: 2025, month: 1, weekSeq: 3 });
165
+ // 2025년 1월 3주차 시작일
166
+
167
+ // US 스타일 (일요일 시작, 첫 주 최소 1일)
168
+ date.getWeekSeqOfYear(0, 1);
137
169
  ```
138
170
 
139
- Immutable time-only class. Values exceeding 24 hours or negative values are automatically normalized with wraparound.
171
+ ### 변경/포맷
140
172
 
141
- **Parsing formats:** `HH:mm:ss`, `HH:mm:ss.fff`, `AM/PM HH:mm:ss`, ISO 8601 (time part extracted).
173
+ ```typescript
174
+ // 변경 메서드 (새 인스턴스 반환)
175
+ date.setYear(2025); date.setMonth(6); date.setDay(20);
176
+ date.addYears(1); date.addMonths(3); date.addDays(10);
177
+
178
+ // 포맷
179
+ date.toFormatString("yyyy-MM-dd"); // "2024-01-15"
180
+ date.toString(); // "2024-01-15"
181
+ ```
142
182
 
143
183
  ---
144
184
 
145
- ## Uuid
185
+ ## Time
186
+
187
+ 불변 시간 전용 타입 (24시간 래핑).
188
+
189
+ ### 생성/파싱
146
190
 
147
191
  ```typescript
148
- class Uuid {
149
- static generate(): Uuid;
150
- static fromBytes(bytes: Bytes): Uuid;
192
+ import { Time } from "@simplysm/core-common";
193
+
194
+ new Time(); // 현재 시각
195
+ new Time(14, 30); // 14:30:00
196
+ new Time(14, 30, 15, 500); // 14:30:15.500
197
+ new Time(tick); // tick(밀리초)으로 생성
198
+ new Time(new Date()); // Date 객체에서 시간 부분만 추출
199
+ Time.parse("14:30:00"); // HH:mm:ss
200
+ Time.parse("14:30:00.123"); // HH:mm:ss.fff
201
+ Time.parse("AM 10:30:00"); // AM/PM HH:mm:ss
202
+ Time.parse("2025-01-15T10:30:00Z"); // ISO 8601 (시간 부분만 추출)
203
+ ```
151
204
 
152
- constructor(uuid: string);
205
+ ### 속성
153
206
 
154
- toString(): string;
155
- toBytes(): Bytes;
156
- }
207
+ | 속성 | 타입 | 설명 |
208
+ |------|------|------|
209
+ | `hour` | `number` | 시 (0~23) |
210
+ | `minute` | `number` | 분 |
211
+ | `second` | `number` | 초 |
212
+ | `millisecond` | `number` | 밀리초 |
213
+ | `tick` | `number` | 하루 기준 밀리초 |
214
+ | `isValid` | `boolean` | 유효성 |
215
+
216
+ ### 24시간 래핑
217
+
218
+ ```typescript
219
+ const time = new Time(23, 0);
220
+ time.addHours(3); // 02:00:00 (다음날로 넘어감)
221
+
222
+ const time2 = new Time(1, 0);
223
+ time2.addHours(-3); // 22:00:00 (이전날로 넘어감)
157
224
  ```
158
225
 
159
- UUID v4 class using `crypto.getRandomValues`. Validates format on construction.
226
+ ### 변경/포맷
227
+
228
+ ```typescript
229
+ // 변경 메서드 (새 인스턴스 반환, 24시간 래핑)
230
+ time.setHour(10); time.setMinute(45);
231
+ time.setSecond(30); time.setMillisecond(500);
232
+ time.addHours(2); time.addMinutes(30);
233
+ time.addSeconds(30); time.addMilliseconds(500);
234
+
235
+ // 포맷
236
+ time.toFormatString("HH:mm:ss"); // "14:30:00"
237
+ time.toString(); // "14:30:00.000"
238
+ ```
160
239
 
161
240
  ---
162
241
 
163
- ## LazyGcMap
242
+ ## Uuid
243
+
244
+ UUID v4 생성/변환. `crypto.getRandomValues` 기반.
164
245
 
165
246
  ```typescript
166
- class LazyGcMap<TKey, TValue> {
167
- constructor(options: {
168
- gcInterval?: number;
169
- expireTime: number;
170
- onExpire?: (key: TKey, value: TValue) => void | Promise<void>;
171
- });
172
-
173
- get size(): number;
174
-
175
- has(key: TKey): boolean;
176
- get(key: TKey): TValue | undefined;
177
- set(key: TKey, value: TValue): void;
178
- delete(key: TKey): boolean;
179
- clear(): void;
180
- getOrCreate(key: TKey, factory: () => TValue): TValue;
181
-
182
- values(): IterableIterator<TValue>;
183
- keys(): IterableIterator<TKey>;
184
- entries(): IterableIterator<[TKey, TValue]>;
185
-
186
- dispose(): void;
187
- [Symbol.dispose](): void;
188
- }
189
- ```
247
+ import { Uuid } from "@simplysm/core-common";
190
248
 
191
- A Map with LRU-style automatic expiration. Access time is updated on `get` and `getOrCreate`. Entries not accessed within `expireTime` are automatically removed. Must call `dispose()` or use `using` statement to stop the GC timer.
249
+ const id = Uuid.generate(); // UUID 생성
250
+ const fromStr = new Uuid("550e8400-e29b-41d4-a716-446655440000");
251
+ const fromBytes = Uuid.fromBytes(bytes); // 16바이트 배열에서 생성 (길이가 16이 아니면 ArgumentError)
252
+ id.toString(); // "xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx"
253
+ id.toBytes(); // Uint8Array (16 bytes)
254
+ ```
192
255
 
193
256
  ---
194
257
 
195
- ## Type Aliases
258
+ ## LazyGcMap
259
+
260
+ 자동 만료 기능이 있는 LRU 캐시. GC 타이머를 사용하므로 반드시 `dispose()` 또는 `using` 문으로 정리해야 한다.
196
261
 
197
262
  ```typescript
198
- type Bytes = Uint8Array;
263
+ import { LazyGcMap } from "@simplysm/core-common";
264
+
265
+ const cache = new LazyGcMap<string, object>({
266
+ expireTime: 60_000, // 60초 만료 (필수)
267
+ gcInterval: 10_000, // 10초마다 GC (기본값: expireTime/10, 최소 1000ms)
268
+ onExpire: (key, value) => { /* 정리 로직, async 가능 */ },
269
+ });
270
+
271
+ cache.set("key", value); // 값 저장 (GC 타이머 시작)
272
+ cache.get("key"); // 값 조회 (접근 시 만료 시간 갱신)
273
+ cache.getOrCreate("key", () => createValue()); // 없으면 생성
274
+ cache.has("key"); // 존재 여부 (접근 시간 갱신 안 함)
275
+ cache.delete("key"); // 삭제
276
+ cache.clear(); // 전체 삭제 (인스턴스는 재사용 가능)
277
+ cache.size; // 저장된 항목 수
278
+
279
+ // 이터레이터
280
+ for (const value of cache.values()) { /* ... */ }
281
+ for (const key of cache.keys()) { /* ... */ }
282
+ for (const [key, value] of cache.entries()) { /* ... */ }
283
+
284
+ // 정리 (Disposable 지원)
285
+ cache.dispose();
286
+ // 또는
287
+ using cache2 = new LazyGcMap({ expireTime: 30_000 });
288
+ ```
199
289
 
200
- type PrimitiveTypeStr = "string" | "number" | "boolean" | "DateTime" | "DateOnly" | "Time" | "Uuid" | "Bytes";
290
+ | 메서드 | 시그니처 | 설명 |
291
+ |--------|---------|------|
292
+ | `get` | `get(key: TKey): TValue \| undefined` | 값 조회 (만료 갱신) |
293
+ | `set` | `set(key: TKey, value: TValue): void` | 값 설정 |
294
+ | `getOrCreate` | `getOrCreate(key: TKey, factory: () => TValue): TValue` | 없으면 생성 |
295
+ | `has` | `has(key: TKey): boolean` | 존재 여부 (만료 갱신 안 함) |
296
+ | `delete` | `delete(key: TKey): boolean` | 삭제 |
297
+ | `clear` | `clear(): void` | 전체 삭제 |
298
+ | `size` | `number` (getter) | 저장된 항목 수 |
299
+ | `values` | `values(): IterableIterator<TValue>` | 값 이터레이터 |
300
+ | `keys` | `keys(): IterableIterator<TKey>` | 키 이터레이터 |
301
+ | `entries` | `entries(): IterableIterator<[TKey, TValue]>` | 엔트리 이터레이터 |
302
+ | `dispose` | `dispose(): void` | GC 타이머 정리 및 데이터 삭제 |
201
303
 
202
- type PrimitiveType = string | number | boolean | DateTime | DateOnly | Time | Uuid | Bytes | undefined;
304
+ ---
305
+
306
+ ## Bytes
203
307
 
204
- type DeepPartial<T> = Partial<{ [K in keyof T]: T[K] extends PrimitiveType ? T[K] : DeepPartial<T[K]> }>;
308
+ `Uint8Array`의 타입 별칭. `Buffer` 대신 사용한다.
205
309
 
206
- interface Type<T> extends Function {
207
- new (...args: unknown[]): T;
208
- }
310
+ ```typescript
311
+ import type { Bytes } from "@simplysm/core-common";
209
312
  ```
210
313
 
211
314
  ---
212
315
 
213
- ## Usage Examples
316
+ ## 공통 타입
214
317
 
215
318
  ```typescript
216
- import { DateTime, DateOnly, Time, Uuid, LazyGcMap } from "@simplysm/core-common";
217
-
218
- // DateTime
219
- const now = new DateTime();
220
- const specific = new DateTime(2025, 3, 15, 10, 30, 0);
221
- const parsed = DateTime.parse("2025-03-15 10:30:00");
222
- const tomorrow = now.addDays(1);
223
- const formatted = now.toFormatString("yyyy-MM-dd HH:mm");
224
-
225
- // DateOnly
226
- const today = new DateOnly();
227
- const week = today.getWeekSeqOfYear(); // { year, weekSeq }
228
-
229
- // Time
230
- const time = new Time(14, 30, 0);
231
- const wrapped = time.addHours(12); // wraps around 24h
232
-
233
- // Uuid
234
- const id = Uuid.generate();
235
- const bytes = id.toBytes();
236
- const restored = Uuid.fromBytes(bytes);
237
-
238
- // LazyGcMap
239
- using cache = new LazyGcMap<string, object>({ expireTime: 60_000 });
240
- cache.set("key", { data: 1 });
241
- const val = cache.getOrCreate("key2", () => ({ data: 2 }));
319
+ // 프리미티브 타입
320
+ type PrimitiveTypeMap = {
321
+ string: string;
322
+ number: number;
323
+ boolean: boolean;
324
+ DateTime: DateTime;
325
+ DateOnly: DateOnly;
326
+ Time: Time;
327
+ Uuid: Uuid;
328
+ Bytes: Bytes;
329
+ };
330
+
331
+ type PrimitiveTypeStr = keyof PrimitiveTypeMap;
332
+ type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined;
333
+
334
+ // 재귀 Partial
335
+ type DeepPartial<T> = Partial<{
336
+ [K in keyof T]: T[K] extends PrimitiveType ? T[K] : DeepPartial<T[K]>;
337
+ }>;
338
+
339
+ // 생성자 타입 (DI용)
340
+ interface Type<T> extends Function { new (...args: unknown[]): T; }
242
341
  ```