@simplysm/core-common 14.0.41 → 14.0.43
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/dist/env.js +1 -1
- package/dist/env.js.map +1 -1
- package/dist/extensions/arr-ext.helpers.js +1 -1
- package/dist/extensions/arr-ext.helpers.js.map +1 -1
- package/dist/extensions/arr-ext.js +25 -25
- package/dist/extensions/arr-ext.js.map +1 -1
- package/dist/types/date-only.js +2 -2
- package/dist/types/date-only.js.map +1 -1
- package/dist/types/date-time.js +2 -2
- package/dist/types/date-time.js.map +1 -1
- package/dist/types/time.js +2 -2
- package/dist/types/time.js.map +1 -1
- package/dist/utils/date-format.js +14 -14
- package/dist/utils/date-format.js.map +1 -1
- package/dist/utils/json.js +3 -3
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/num.js +1 -1
- package/dist/utils/num.js.map +1 -1
- package/dist/utils/obj.d.ts.map +1 -1
- package/dist/utils/obj.js +14 -15
- package/dist/utils/obj.js.map +1 -1
- package/dist/utils/template-strings.js +1 -1
- package/dist/utils/template-strings.js.map +1 -1
- package/dist/utils/transferable.js +9 -9
- package/dist/utils/transferable.js.map +1 -1
- package/dist/utils/wait.js +1 -1
- package/dist/utils/wait.js.map +1 -1
- package/dist/utils/xml.js +1 -1
- package/dist/utils/xml.js.map +1 -1
- package/dist/utils/zip.js +1 -1
- package/dist/utils/zip.js.map +1 -1
- package/package.json +2 -2
- package/src/env.ts +1 -1
- package/src/extensions/arr-ext.helpers.ts +1 -1
- package/src/extensions/arr-ext.ts +25 -25
- package/src/types/date-only.ts +2 -2
- package/src/types/date-time.ts +2 -2
- package/src/types/time.ts +2 -2
- package/src/utils/date-format.ts +14 -14
- package/src/utils/json.ts +3 -3
- package/src/utils/num.ts +1 -1
- package/src/utils/obj.ts +14 -16
- package/src/utils/template-strings.ts +1 -1
- package/src/utils/transferable.ts +9 -9
- package/src/utils/wait.ts +1 -1
- package/src/utils/xml.ts +1 -1
- package/src/utils/zip.ts +1 -1
|
@@ -26,7 +26,7 @@ import type {
|
|
|
26
26
|
|
|
27
27
|
const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
28
28
|
single<T>(predicate?: (item: T, index: number) => boolean): T | undefined {
|
|
29
|
-
const arr = predicate
|
|
29
|
+
const arr = predicate != null ? this.filter(predicate) : this;
|
|
30
30
|
if (arr.length > 1) {
|
|
31
31
|
throw new ArgumentError("여러 개의 결과가 발견되었습니다.", { count: arr.length });
|
|
32
32
|
}
|
|
@@ -34,7 +34,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
34
34
|
},
|
|
35
35
|
|
|
36
36
|
first<T>(predicate?: (item: T, index: number) => boolean): T | undefined {
|
|
37
|
-
return predicate
|
|
37
|
+
return predicate != null ? this.find(predicate) : this[0];
|
|
38
38
|
},
|
|
39
39
|
|
|
40
40
|
async filterAsync<T>(predicate: (item: T, index: number) => Promise<boolean>): Promise<T[]> {
|
|
@@ -48,7 +48,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
48
48
|
},
|
|
49
49
|
|
|
50
50
|
last<T>(predicate?: (item: T, index: number) => boolean): T | undefined {
|
|
51
|
-
if (predicate
|
|
51
|
+
if (predicate != null) {
|
|
52
52
|
for (let i = this.length - 1; i >= 0; i--) {
|
|
53
53
|
if (predicate(this[i], i)) {
|
|
54
54
|
return this[i];
|
|
@@ -113,7 +113,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
113
113
|
},
|
|
114
114
|
|
|
115
115
|
async mapManyAsync<T, R>(selector?: (item: T, index: number) => Promise<R[]>): Promise<T | R[]> {
|
|
116
|
-
const arr = selector
|
|
116
|
+
const arr = selector != null ? await this.mapAsync(selector) : this;
|
|
117
117
|
return arr.mapMany();
|
|
118
118
|
},
|
|
119
119
|
|
|
@@ -139,13 +139,13 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
139
139
|
|
|
140
140
|
for (let i = 0; i < this.length; i++) {
|
|
141
141
|
const keyObj = keySelector(this[i], i);
|
|
142
|
-
const valueObj = valueSelector
|
|
142
|
+
const valueObj = valueSelector != null ? valueSelector(this[i], i) : this[i];
|
|
143
143
|
|
|
144
144
|
// 원시 key는 Map을 사용하여 O(n)으로 처리
|
|
145
145
|
if (keyObj == null || typeof keyObj !== "object") {
|
|
146
146
|
const keyStr = typeof keyObj + ":" + String(keyObj);
|
|
147
147
|
const existingIndex = primitiveKeyIndex.get(keyStr);
|
|
148
|
-
if (existingIndex
|
|
148
|
+
if (existingIndex != null) {
|
|
149
149
|
result[existingIndex].values.push(valueObj);
|
|
150
150
|
} else {
|
|
151
151
|
primitiveKeyIndex.set(keyStr, result.length);
|
|
@@ -156,7 +156,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
156
156
|
|
|
157
157
|
// 객체 key는 기존 방식 O(n²) 사용
|
|
158
158
|
const existsRecord = result.find((item) => equal(item.key, keyObj));
|
|
159
|
-
if (existsRecord
|
|
159
|
+
if (existsRecord != null) {
|
|
160
160
|
existsRecord.values.push(valueObj);
|
|
161
161
|
} else {
|
|
162
162
|
result.push({ key: keyObj, values: [valueObj] });
|
|
@@ -176,7 +176,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
176
176
|
const item = this[i];
|
|
177
177
|
|
|
178
178
|
const keyObj = keySelector(item, i);
|
|
179
|
-
const valueObj = valueSelector
|
|
179
|
+
const valueObj = valueSelector != null ? valueSelector(item, i) : item;
|
|
180
180
|
|
|
181
181
|
if (result.has(keyObj)) {
|
|
182
182
|
throw new ArgumentError("중복된 key입니다.", { duplicatedKey: keyObj });
|
|
@@ -197,7 +197,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
197
197
|
const item = this[i];
|
|
198
198
|
|
|
199
199
|
const keyObj = await keySelector(item, i);
|
|
200
|
-
const valueObj = valueSelector
|
|
200
|
+
const valueObj = valueSelector != null ? await valueSelector(item, i) : item;
|
|
201
201
|
|
|
202
202
|
if (result.has(keyObj)) {
|
|
203
203
|
throw new ArgumentError("중복된 key입니다.", { duplicatedKey: keyObj });
|
|
@@ -218,7 +218,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
218
218
|
const item = this[i];
|
|
219
219
|
|
|
220
220
|
const keyObj = keySelector(item, i);
|
|
221
|
-
const valueObj = valueSelector
|
|
221
|
+
const valueObj = valueSelector != null ? valueSelector(item, i) : item;
|
|
222
222
|
|
|
223
223
|
const arr = result.getOrCreate(keyObj, []);
|
|
224
224
|
arr.push(valueObj);
|
|
@@ -237,7 +237,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
237
237
|
const item = this[i];
|
|
238
238
|
|
|
239
239
|
const keyObj = keySelector(item, i);
|
|
240
|
-
const valueObj = valueSelector
|
|
240
|
+
const valueObj = valueSelector != null ? valueSelector(item, i) : item;
|
|
241
241
|
|
|
242
242
|
const set = result.getOrCreate(keyObj, new Set<V | T>());
|
|
243
243
|
set.add(valueObj);
|
|
@@ -280,10 +280,10 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
280
280
|
const item = this[i];
|
|
281
281
|
|
|
282
282
|
const key = keySelector(item, i);
|
|
283
|
-
const valueObj = valueSelector
|
|
283
|
+
const valueObj = valueSelector != null ? valueSelector(item, i) : item;
|
|
284
284
|
|
|
285
285
|
// undefined 값은 "없음"으로 처리하여 덮어쓰기 허용
|
|
286
|
-
if (result[key]
|
|
286
|
+
if (result[key] != null) {
|
|
287
287
|
throw new ArgumentError("중복된 key입니다.", { duplicatedKey: key });
|
|
288
288
|
}
|
|
289
289
|
result[key] = valueObj;
|
|
@@ -345,7 +345,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
345
345
|
|
|
346
346
|
const uncheckedTarget = [...target];
|
|
347
347
|
const uncheckedTargetSet = new Set(uncheckedTarget);
|
|
348
|
-
const hasKeys = options?.keys
|
|
348
|
+
const hasKeys = options?.keys != null && options.keys.length > 0;
|
|
349
349
|
const excludeOpts = { topLevelExcludes: options?.excludes };
|
|
350
350
|
|
|
351
351
|
// keys 옵션이 제공되면 target을 Map으로 사전 인덱싱하여 O(n×m) → O(n+m)으로 개선
|
|
@@ -381,7 +381,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
381
381
|
}
|
|
382
382
|
|
|
383
383
|
// 전체 일치가 없고 keys 옵션이 있으면 Map에서 O(1) 조회 수행
|
|
384
|
-
if (sameTarget
|
|
384
|
+
if (sameTarget == null && keyIndexedTarget) {
|
|
385
385
|
const sourceKeyStr = JSON.stringify(
|
|
386
386
|
options!.keys!.map((k) => (sourceItem as Record<string, unknown>)[k]),
|
|
387
387
|
);
|
|
@@ -392,9 +392,9 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
392
392
|
}
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
if (sameTarget
|
|
395
|
+
if (sameTarget != null) {
|
|
396
396
|
uncheckedTargetSet.delete(sameTarget);
|
|
397
|
-
} else if (sameKeyTarget
|
|
397
|
+
} else if (sameKeyTarget != null) {
|
|
398
398
|
result.push({ source: sourceItem, target: sameKeyTarget });
|
|
399
399
|
uncheckedTargetSet.delete(sameKeyTarget);
|
|
400
400
|
} else {
|
|
@@ -481,15 +481,15 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
481
481
|
|
|
482
482
|
for (const diff of diffs) {
|
|
483
483
|
// 업데이트 시
|
|
484
|
-
if (diff.source
|
|
484
|
+
if (diff.source != null && diff.target != null) {
|
|
485
485
|
const sourceIndex = sourceIndexMap.get(diff.source);
|
|
486
|
-
if (sourceIndex
|
|
486
|
+
if (sourceIndex == null) {
|
|
487
487
|
throw new SdError("예상치 못한 오류: merge에서 source 항목을 찾을 수 없습니다.");
|
|
488
488
|
}
|
|
489
489
|
result[sourceIndex] = merge(diff.source, diff.target);
|
|
490
490
|
}
|
|
491
491
|
// 추가 시
|
|
492
|
-
else if (diff.target
|
|
492
|
+
else if (diff.target != null) {
|
|
493
493
|
result.push(diff.target);
|
|
494
494
|
}
|
|
495
495
|
}
|
|
@@ -500,7 +500,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
500
500
|
sum<T>(selector?: (item: T, index: number) => number): number {
|
|
501
501
|
let result = 0;
|
|
502
502
|
for (let i = 0; i < this.length; i++) {
|
|
503
|
-
const item = selector
|
|
503
|
+
const item = selector != null ? selector(this[i], i) : this[i];
|
|
504
504
|
if (typeof item !== "number") {
|
|
505
505
|
throw new ArgumentError("sum은 숫자에만 사용할 수 있습니다.", {
|
|
506
506
|
type: typeof item,
|
|
@@ -515,13 +515,13 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
515
515
|
min<T>(selector?: (item: T, index: number) => string | number): string | number | undefined {
|
|
516
516
|
let result: string | number | undefined;
|
|
517
517
|
for (let i = 0; i < this.length; i++) {
|
|
518
|
-
const item = selector
|
|
518
|
+
const item = selector != null ? selector(this[i], i) : this[i];
|
|
519
519
|
if (typeof item !== "number" && typeof item !== "string") {
|
|
520
520
|
throw new ArgumentError("min은 숫자/문자열에만 사용할 수 있습니다.", {
|
|
521
521
|
type: typeof item,
|
|
522
522
|
});
|
|
523
523
|
}
|
|
524
|
-
if (result
|
|
524
|
+
if (result == null || result > item) {
|
|
525
525
|
result = item;
|
|
526
526
|
}
|
|
527
527
|
}
|
|
@@ -532,13 +532,13 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
532
532
|
max<T>(selector?: (item: T, index: number) => string | number): string | number | undefined {
|
|
533
533
|
let result: string | number | undefined;
|
|
534
534
|
for (let i = 0; i < this.length; i++) {
|
|
535
|
-
const item = selector
|
|
535
|
+
const item = selector != null ? selector(this[i], i) : this[i];
|
|
536
536
|
if (typeof item !== "number" && typeof item !== "string") {
|
|
537
537
|
throw new ArgumentError("max는 숫자/문자열에만 사용할 수 있습니다.", {
|
|
538
538
|
type: typeof item,
|
|
539
539
|
});
|
|
540
540
|
}
|
|
541
|
-
if (result
|
|
541
|
+
if (result == null || result < item) {
|
|
542
542
|
result = item;
|
|
543
543
|
}
|
|
544
544
|
}
|
package/src/types/date-only.ts
CHANGED
|
@@ -26,11 +26,11 @@ export class DateOnly {
|
|
|
26
26
|
/** Date 타입으로 생성 */
|
|
27
27
|
constructor(date: Date);
|
|
28
28
|
constructor(arg1?: number | Date, arg2?: number, arg3?: number) {
|
|
29
|
-
if (arg1
|
|
29
|
+
if (arg1 == null) {
|
|
30
30
|
const tick = Date.now();
|
|
31
31
|
const date = new Date(tick);
|
|
32
32
|
this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
33
|
-
} else if (arg2
|
|
33
|
+
} else if (arg2 != null && arg3 != null) {
|
|
34
34
|
this.date = new Date(arg1 as number, arg2 - 1, arg3);
|
|
35
35
|
} else if (arg1 instanceof Date) {
|
|
36
36
|
const date = arg1;
|
package/src/types/date-time.ts
CHANGED
|
@@ -40,9 +40,9 @@ export class DateTime {
|
|
|
40
40
|
arg6?: number,
|
|
41
41
|
arg7?: number,
|
|
42
42
|
) {
|
|
43
|
-
if (arg1
|
|
43
|
+
if (arg1 == null) {
|
|
44
44
|
this.date = new Date();
|
|
45
|
-
} else if (arg2
|
|
45
|
+
} else if (arg2 != null && arg3 != null) {
|
|
46
46
|
this.date = new Date(
|
|
47
47
|
arg1 as number,
|
|
48
48
|
arg2 - 1,
|
package/src/types/time.ts
CHANGED
|
@@ -26,7 +26,7 @@ export class Time {
|
|
|
26
26
|
/** Date 객체에서 시간 부분만 추출하여 생성 */
|
|
27
27
|
constructor(date: Date);
|
|
28
28
|
constructor(arg1?: number | Date, arg2?: number, arg3?: number, arg4?: number) {
|
|
29
|
-
if (arg1
|
|
29
|
+
if (arg1 == null) {
|
|
30
30
|
const now = new Date();
|
|
31
31
|
this._tick =
|
|
32
32
|
(now.getMilliseconds() +
|
|
@@ -34,7 +34,7 @@ export class Time {
|
|
|
34
34
|
now.getMinutes() * 60 * 1000 +
|
|
35
35
|
now.getHours() * 60 * 60 * 1000) %
|
|
36
36
|
Time._MS_PER_DAY;
|
|
37
|
-
} else if (arg2
|
|
37
|
+
} else if (arg2 != null) {
|
|
38
38
|
let tick =
|
|
39
39
|
((arg4 ?? 0) + (arg3 ?? 0) * 1000 + arg2 * 60 * 1000 + (arg1 as number) * 60 * 60 * 1000) %
|
|
40
40
|
Time._MS_PER_DAY;
|
package/src/utils/date-format.ts
CHANGED
|
@@ -152,47 +152,47 @@ export function format(
|
|
|
152
152
|
const { year, month, day, hour, minute, second, millisecond, timezoneOffsetMinutes } = args;
|
|
153
153
|
|
|
154
154
|
const absOffsetMinutes =
|
|
155
|
-
timezoneOffsetMinutes
|
|
156
|
-
const offsetHour = absOffsetMinutes
|
|
157
|
-
const offsetMinute = absOffsetMinutes
|
|
155
|
+
timezoneOffsetMinutes != null ? Math.abs(timezoneOffsetMinutes) : undefined;
|
|
156
|
+
const offsetHour = absOffsetMinutes != null ? Math.floor(absOffsetMinutes / 60) : undefined;
|
|
157
|
+
const offsetMinute = absOffsetMinutes != null ? absOffsetMinutes % 60 : undefined;
|
|
158
158
|
const offsetSign =
|
|
159
|
-
timezoneOffsetMinutes
|
|
159
|
+
timezoneOffsetMinutes != null ? (timezoneOffsetMinutes >= 0 ? "+" : "-") : undefined;
|
|
160
160
|
|
|
161
161
|
const week =
|
|
162
|
-
year
|
|
162
|
+
year != null && month != null && day != null
|
|
163
163
|
? new Date(year, month - 1, day).getDay()
|
|
164
164
|
: undefined;
|
|
165
165
|
|
|
166
166
|
let result = formatString;
|
|
167
167
|
|
|
168
168
|
// 연도
|
|
169
|
-
if (year
|
|
169
|
+
if (year != null) {
|
|
170
170
|
const yearStr = year.toString();
|
|
171
171
|
result = result.replace(patterns.yyyy, yearStr);
|
|
172
172
|
result = result.replace(patterns.yy, yearStr.substring(2, 4));
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
// 월
|
|
176
|
-
if (month
|
|
176
|
+
if (month != null) {
|
|
177
177
|
const monthStr = month.toString();
|
|
178
178
|
result = result.replace(patterns.MM, monthStr.padStart(2, "0"));
|
|
179
179
|
result = result.replace(patterns.M, monthStr);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
// 요일
|
|
183
|
-
if (week
|
|
183
|
+
if (week != null) {
|
|
184
184
|
result = result.replace(patterns.ddd, weekStrings[week]);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
// 일
|
|
188
|
-
if (day
|
|
188
|
+
if (day != null) {
|
|
189
189
|
const dayStr = day.toString();
|
|
190
190
|
result = result.replace(patterns.dd, dayStr.padStart(2, "0"));
|
|
191
191
|
result = result.replace(patterns.d, dayStr);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// 시
|
|
195
|
-
if (hour
|
|
195
|
+
if (hour != null) {
|
|
196
196
|
result = result.replace(patterns.tt, hour < 12 ? "AM" : "PM");
|
|
197
197
|
|
|
198
198
|
const hour12 = hour % 12 || 12;
|
|
@@ -206,21 +206,21 @@ export function format(
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// 분
|
|
209
|
-
if (minute
|
|
209
|
+
if (minute != null) {
|
|
210
210
|
const minuteStr = minute.toString();
|
|
211
211
|
result = result.replace(patterns.mm, minuteStr.padStart(2, "0"));
|
|
212
212
|
result = result.replace(patterns.m, minuteStr);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
// 초
|
|
216
|
-
if (second
|
|
216
|
+
if (second != null) {
|
|
217
217
|
const secondStr = second.toString();
|
|
218
218
|
result = result.replace(patterns.ss, secondStr.padStart(2, "0"));
|
|
219
219
|
result = result.replace(patterns.s, secondStr);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
// 밀리초
|
|
223
|
-
if (millisecond
|
|
223
|
+
if (millisecond != null) {
|
|
224
224
|
const msStr = millisecond.toString().padStart(3, "0");
|
|
225
225
|
result = result.replace(patterns.fff, msStr);
|
|
226
226
|
result = result.replace(patterns.ff, msStr.substring(0, 2));
|
|
@@ -228,7 +228,7 @@ export function format(
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
// 타임존
|
|
231
|
-
if (offsetSign
|
|
231
|
+
if (offsetSign != null && offsetHour != null && offsetMinute != null) {
|
|
232
232
|
result = result.replace(
|
|
233
233
|
patterns.zzz,
|
|
234
234
|
`${offsetSign}${offsetHour.toString().padStart(2, "0")}:${offsetMinute.toString().padStart(2, "0")}`,
|
package/src/utils/json.ts
CHANGED
|
@@ -56,7 +56,7 @@ export function stringify(
|
|
|
56
56
|
*/
|
|
57
57
|
const convertSpecialTypes = (key: string | undefined, value: unknown): unknown => {
|
|
58
58
|
// 커스텀 replacer 적용
|
|
59
|
-
const currValue = options?.replacer
|
|
59
|
+
const currValue = options?.replacer != null ? options.replacer(key, value) : value;
|
|
60
60
|
|
|
61
61
|
if (currValue instanceof Date) {
|
|
62
62
|
return { __type__: "Date", data: currValue.toISOString() };
|
|
@@ -121,7 +121,7 @@ export function stringify(
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// 일반 객체 처리
|
|
124
|
-
if (currValue
|
|
124
|
+
if (currValue != null && typeof currValue === "object") {
|
|
125
125
|
// 순환 참조 감지
|
|
126
126
|
if (seen.has(currValue)) {
|
|
127
127
|
throw new TypeError("Converting circular structure to JSON");
|
|
@@ -142,7 +142,7 @@ export function stringify(
|
|
|
142
142
|
for (const [k, v] of Object.entries(currValue)) {
|
|
143
143
|
const converted = convertSpecialTypes(k, v);
|
|
144
144
|
// undefined는 JSON에서 제외됨
|
|
145
|
-
if (converted
|
|
145
|
+
if (converted != null) {
|
|
146
146
|
result[k] = converted;
|
|
147
147
|
}
|
|
148
148
|
}
|
package/src/utils/num.ts
CHANGED
|
@@ -29,7 +29,7 @@ export function parseInt(text: unknown): number | undefined {
|
|
|
29
29
|
*/
|
|
30
30
|
export function parseRoundedInt(text: unknown): number | undefined {
|
|
31
31
|
const float = parseFloat(text);
|
|
32
|
-
return float
|
|
32
|
+
return float != null ? Math.round(float) : undefined;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
package/src/utils/obj.ts
CHANGED
|
@@ -22,7 +22,7 @@ export function clone<TObj>(source: TObj): TObj {
|
|
|
22
22
|
|
|
23
23
|
function cloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): unknown {
|
|
24
24
|
// 원시 값은 그대로 반환
|
|
25
|
-
if (typeof source !== "object" || source
|
|
25
|
+
if (typeof source !== "object" || source == null) {
|
|
26
26
|
return source;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -66,14 +66,14 @@ function cloneImpl(source: unknown, prevClones?: WeakMap<object, unknown>): unkn
|
|
|
66
66
|
cloned.message = source.message;
|
|
67
67
|
cloned.name = source.name;
|
|
68
68
|
cloned.stack = source.stack;
|
|
69
|
-
if (source.cause
|
|
69
|
+
if (source.cause != null) {
|
|
70
70
|
cloned.cause = cloneImpl(source.cause, currPrevClones);
|
|
71
71
|
}
|
|
72
72
|
// 커스텀 Error 속성 복사
|
|
73
73
|
for (const key of Object.keys(source)) {
|
|
74
74
|
if (!["message", "name", "stack", "cause"].includes(key)) {
|
|
75
75
|
const desc = Object.getOwnPropertyDescriptor(source, key);
|
|
76
|
-
if (desc
|
|
76
|
+
if (desc != null) {
|
|
77
77
|
Object.defineProperty(cloned, key, {
|
|
78
78
|
...desc,
|
|
79
79
|
value: "value" in desc ? cloneImpl(desc.value, currPrevClones) : desc.value,
|
|
@@ -352,13 +352,13 @@ function equalObject(
|
|
|
352
352
|
): boolean {
|
|
353
353
|
const sourceKeys = Object.keys(source).filter(
|
|
354
354
|
(key) =>
|
|
355
|
-
(options?.topLevelIncludes
|
|
355
|
+
(options?.topLevelIncludes == null || options.topLevelIncludes.includes(key)) &&
|
|
356
356
|
!options?.topLevelExcludes?.includes(key) &&
|
|
357
357
|
source[key] != null,
|
|
358
358
|
);
|
|
359
359
|
const targetKeys = Object.keys(target).filter(
|
|
360
360
|
(key) =>
|
|
361
|
-
(options?.topLevelIncludes
|
|
361
|
+
(options?.topLevelIncludes == null || options.topLevelIncludes.includes(key)) &&
|
|
362
362
|
!options?.topLevelExcludes?.includes(key) &&
|
|
363
363
|
target[key] != null,
|
|
364
364
|
);
|
|
@@ -460,16 +460,14 @@ export function merge<TSource, TMergeTarget>(
|
|
|
460
460
|
return clone(target) as TSource & TMergeTarget;
|
|
461
461
|
}
|
|
462
462
|
|
|
463
|
-
if (target
|
|
463
|
+
if (target == null) {
|
|
464
|
+
// null(typeof "object")이면 useDelTargetNull 옵션 적용, undefined면 항상 clone
|
|
465
|
+
if (typeof target === "object" && opt?.useDelTargetNull) {
|
|
466
|
+
return undefined as TSource & TMergeTarget;
|
|
467
|
+
}
|
|
464
468
|
return clone(source) as TSource & TMergeTarget;
|
|
465
469
|
}
|
|
466
470
|
|
|
467
|
-
if (target === null) {
|
|
468
|
-
return opt?.useDelTargetNull
|
|
469
|
-
? (undefined as TSource & TMergeTarget)
|
|
470
|
-
: (clone(source) as TSource & TMergeTarget);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
471
|
if (typeof target !== "object") {
|
|
474
472
|
return target as TSource & TMergeTarget;
|
|
475
473
|
}
|
|
@@ -506,7 +504,7 @@ export function merge<TSource, TMergeTarget>(
|
|
|
506
504
|
if (opt?.arrayProcess === "concat" && source instanceof Array && target instanceof Array) {
|
|
507
505
|
let result = [...new Set([...source, ...target])];
|
|
508
506
|
if (opt.useDelTargetNull) {
|
|
509
|
-
result = result.filter((item) => item
|
|
507
|
+
result = result.filter((item) => item != null);
|
|
510
508
|
}
|
|
511
509
|
return result as TSource & TMergeTarget;
|
|
512
510
|
}
|
|
@@ -516,7 +514,7 @@ export function merge<TSource, TMergeTarget>(
|
|
|
516
514
|
const resultRec = clone(sourceRec);
|
|
517
515
|
for (const key of Object.keys(target)) {
|
|
518
516
|
resultRec[key] = merge(sourceRec[key], targetRec[key], opt);
|
|
519
|
-
if (resultRec[key]
|
|
517
|
+
if (resultRec[key] == null) {
|
|
520
518
|
delete resultRec[key];
|
|
521
519
|
}
|
|
522
520
|
}
|
|
@@ -706,7 +704,7 @@ export function getChainValue(
|
|
|
706
704
|
const splits = getChainSplits(chain);
|
|
707
705
|
let result: unknown = obj;
|
|
708
706
|
for (const splitItem of splits) {
|
|
709
|
-
if (optional && result
|
|
707
|
+
if (optional && result == null) {
|
|
710
708
|
result = undefined;
|
|
711
709
|
} else {
|
|
712
710
|
result = (result as Record<string | number, unknown>)[splitItem];
|
|
@@ -813,7 +811,7 @@ export function deleteChainValue(obj: unknown, chain: string): void {
|
|
|
813
811
|
export function clearUndefined<T extends object>(obj: T): T {
|
|
814
812
|
const record = obj as Record<string, unknown>;
|
|
815
813
|
for (const key of Object.keys(record)) {
|
|
816
|
-
if (record[key]
|
|
814
|
+
if (record[key] == null) {
|
|
817
815
|
delete record[key];
|
|
818
816
|
}
|
|
819
817
|
}
|
|
@@ -102,7 +102,7 @@ export function pgsql(strings: TemplateStringsArray, ...values: unknown[]): stri
|
|
|
102
102
|
|
|
103
103
|
function _combine(strings: TemplateStringsArray, values: unknown[]): string {
|
|
104
104
|
const raw = strings.reduce((result, str, i) => {
|
|
105
|
-
const value = values[i]
|
|
105
|
+
const value = values[i] != null ? String(values[i]) : "";
|
|
106
106
|
return result + str + value;
|
|
107
107
|
}, "");
|
|
108
108
|
return _trimIndent(raw);
|
|
@@ -73,7 +73,7 @@ function encodeImpl(
|
|
|
73
73
|
|
|
74
74
|
// 이미 인코딩된 객체이면 캐싱된 결과 재사용
|
|
75
75
|
const cached = cache.get(obj);
|
|
76
|
-
if (cached
|
|
76
|
+
if (cached != null) return cached;
|
|
77
77
|
|
|
78
78
|
// 재귀 스택에 추가
|
|
79
79
|
ancestors.add(obj);
|
|
@@ -118,8 +118,8 @@ function encodeImpl(
|
|
|
118
118
|
name: errObj.name,
|
|
119
119
|
message: errObj.message,
|
|
120
120
|
stack: errObj.stack,
|
|
121
|
-
...(errObj.code
|
|
122
|
-
...(errObj.detail
|
|
121
|
+
...(errObj.code != null ? { code: errObj.code } : {}),
|
|
122
|
+
...(errObj.detail != null
|
|
123
123
|
? {
|
|
124
124
|
detail: encodeImpl(
|
|
125
125
|
errObj.detail,
|
|
@@ -130,7 +130,7 @@ function encodeImpl(
|
|
|
130
130
|
),
|
|
131
131
|
}
|
|
132
132
|
: {}),
|
|
133
|
-
...(errObj.cause
|
|
133
|
+
...(errObj.cause != null
|
|
134
134
|
? {
|
|
135
135
|
cause: encodeImpl(errObj.cause, transferList, [...path, "cause"], ancestors, cache),
|
|
136
136
|
}
|
|
@@ -217,11 +217,11 @@ export function decode(obj: unknown): unknown {
|
|
|
217
217
|
if (typed.__type__ === "DateOnly" && typeof data === "number") return new DateOnly(data);
|
|
218
218
|
if (typed.__type__ === "Time" && typeof data === "number") return new Time(data);
|
|
219
219
|
if (typed.__type__ === "Uuid" && typeof data === "string") return new Uuid(data);
|
|
220
|
-
if (typed.__type__ === "RegExp" && typeof data === "object" && data
|
|
220
|
+
if (typed.__type__ === "RegExp" && typeof data === "object" && data != null) {
|
|
221
221
|
const regexData = data as { source: string; flags: string };
|
|
222
222
|
return new RegExp(regexData.source, regexData.flags);
|
|
223
223
|
}
|
|
224
|
-
if (typed.__type__ === "Error" && typeof data === "object" && data
|
|
224
|
+
if (typed.__type__ === "Error" && typeof data === "object" && data != null) {
|
|
225
225
|
const errorData = data as {
|
|
226
226
|
name: string;
|
|
227
227
|
message: string;
|
|
@@ -238,9 +238,9 @@ export function decode(obj: unknown): unknown {
|
|
|
238
238
|
err.name = errorData.name;
|
|
239
239
|
err.stack = errorData.stack;
|
|
240
240
|
|
|
241
|
-
if (errorData.code
|
|
242
|
-
if (errorData.cause
|
|
243
|
-
if (errorData.detail
|
|
241
|
+
if (errorData.code != null) err.code = errorData.code;
|
|
242
|
+
if (errorData.cause != null) (err as Error).cause = decode(errorData.cause);
|
|
243
|
+
if (errorData.detail != null) err.detail = decode(errorData.detail);
|
|
244
244
|
return err;
|
|
245
245
|
}
|
|
246
246
|
}
|
package/src/utils/wait.ts
CHANGED
package/src/utils/xml.ts
CHANGED
|
@@ -79,7 +79,7 @@ function stripTagPrefix(obj: unknown): unknown {
|
|
|
79
79
|
return obj.map((item) => stripTagPrefix(item));
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
if (typeof obj === "object" && obj
|
|
82
|
+
if (typeof obj === "object" && obj != null) {
|
|
83
83
|
const newObj: Record<string, unknown> = {};
|
|
84
84
|
const record = obj as Record<string, unknown>;
|
|
85
85
|
|