@simplysm/core-common 14.0.1 → 14.0.4

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/utils.md ADDED
@@ -0,0 +1,641 @@
1
+ # Utils
2
+
3
+ Namespace-exported utility functions and standalone exports. Import as `import { obj, str, num, ... } from "@simplysm/core-common"`.
4
+
5
+ ## `obj` -- Object Utilities
6
+
7
+ ### `obj.clone<T>(source: T): T`
8
+
9
+ Deep clone with support for circular references and custom types (DateTime, DateOnly, Time, Uuid, Uint8Array, Date, RegExp, Map, Set, Error). Preserves prototype chain. Functions and Symbols are kept as references.
10
+
11
+ ```typescript
12
+ const cloned = obj.clone({ a: 1, b: new DateTime() });
13
+ ```
14
+
15
+ ### `obj.equal(source, target, options?): boolean`
16
+
17
+ Deep equality comparison.
18
+
19
+ ```typescript
20
+ function equal(source: unknown, target: unknown, options?: EqualOptions): boolean;
21
+ ```
22
+
23
+ **`EqualOptions`:**
24
+
25
+ | Field | Type | Description |
26
+ |-------|------|-------------|
27
+ | `topLevelIncludes` | `string[]` | Only compare these top-level keys |
28
+ | `topLevelExcludes` | `string[]` | Exclude these top-level keys from comparison |
29
+ | `ignoreArrayIndex` | `boolean` | Ignore array order (O(n^2)) |
30
+ | `shallow` | `boolean` | Compare only one level deep (reference equality for nested) |
31
+
32
+ Supports: Date, DateTime, DateOnly, Time, Uuid, RegExp, Array, Map, Set, plain objects.
33
+
34
+ ### `obj.merge<S, T>(source: S, target: T, opt?): S & T`
35
+
36
+ Deep merge. Returns a new object (immutable).
37
+
38
+ ```typescript
39
+ function merge<S, T>(source: S, target: T, opt?: MergeOptions): S & T;
40
+ ```
41
+
42
+ **`MergeOptions`:**
43
+
44
+ | Field | Type | Default | Description |
45
+ |-------|------|---------|-------------|
46
+ | `arrayProcess` | `"replace" \| "concat"` | `"replace"` | How to handle arrays. `"concat"` deduplicates via Set |
47
+ | `useDelTargetNull` | `boolean` | `false` | If `true`, `null` target values delete the key |
48
+
49
+ ### `obj.merge3<S, O, T>(source, origin, target, optionsObj?)`
50
+
51
+ 3-way merge. Compares source and target against a common origin.
52
+
53
+ ```typescript
54
+ function merge3<S, O, T>(
55
+ source: S, origin: O, target: T,
56
+ optionsObj?: Record<string, Merge3KeyOptions>,
57
+ ): { conflict: boolean; result: O & S & T };
58
+ ```
59
+
60
+ **`Merge3KeyOptions`:**
61
+
62
+ | Field | Type | Description |
63
+ |-------|------|-------------|
64
+ | `keys` | `string[]` | Sub-keys to compare |
65
+ | `excludes` | `string[]` | Sub-keys to exclude |
66
+ | `ignoreArrayIndex` | `boolean` | Ignore array order |
67
+
68
+ Rules: origin -> source change wins; origin -> target change wins; both changed same way = ok; both changed differently = conflict (origin value kept).
69
+
70
+ ### `obj.omit<T, K>(item, omitKeys): Omit<T, K>`
71
+
72
+ Returns a new object excluding the specified keys.
73
+
74
+ ```typescript
75
+ obj.omit({ a: 1, b: 2, c: 3 }, ["c"]); // { a: 1, b: 2 }
76
+ ```
77
+
78
+ ### `obj.omitByFilter<T>(item, omitKeyFn): T`
79
+
80
+ Returns a new object excluding keys where the predicate returns `true`.
81
+
82
+ ```typescript
83
+ obj.omitByFilter({ name: "a", _internal: "x" }, (k) => k.startsWith("_"));
84
+ ```
85
+
86
+ ### `obj.pick<T, K>(item, pickKeys): Pick<T, K>`
87
+
88
+ Returns a new object with only the specified keys.
89
+
90
+ ```typescript
91
+ obj.pick({ a: 1, b: 2, c: 3 }, ["a", "b"]); // { a: 1, b: 2 }
92
+ ```
93
+
94
+ ### `obj.getChainValue(obj, chain, optional?): unknown`
95
+
96
+ Access a deeply nested value using a dot/bracket chain string.
97
+
98
+ ```typescript
99
+ obj.getChainValue(data, "a.b[0].c");
100
+ obj.getChainValue(data, "a?.b?.c", true); // returns undefined if intermediate is missing
101
+ ```
102
+
103
+ ### `obj.getChainValueByDepth<T, K>(obj, key, depth, optional?)`
104
+
105
+ Descend into the same key repeatedly by a given depth.
106
+
107
+ ```typescript
108
+ obj.getChainValueByDepth({ parent: { parent: { name: "root" } } }, "parent", 2);
109
+ // { name: "root" }
110
+ ```
111
+
112
+ ### `obj.setChainValue(obj, chain, value): void`
113
+
114
+ Set a deeply nested value. Creates intermediate objects as needed.
115
+
116
+ ```typescript
117
+ obj.setChainValue(data, "a.b[0].c", 42);
118
+ ```
119
+
120
+ ### `obj.deleteChainValue(obj, chain): void`
121
+
122
+ Delete a deeply nested value.
123
+
124
+ ```typescript
125
+ obj.deleteChainValue(data, "a.b[0].c");
126
+ ```
127
+
128
+ ### `obj.clearUndefined<T>(obj): T`
129
+
130
+ Mutates: deletes keys with `undefined` values from an object.
131
+
132
+ ### `obj.clear<T>(obj): Record<string, never>`
133
+
134
+ Mutates: deletes all keys from an object.
135
+
136
+ ### `obj.nullToUndefined<T>(obj): T | undefined`
137
+
138
+ Mutates: recursively converts all `null` values to `undefined`.
139
+
140
+ ### `obj.unflatten(flatObj): Record<string, unknown>`
141
+
142
+ Converts a flat dotted-key object to a nested object.
143
+
144
+ ```typescript
145
+ obj.unflatten({ "a.b.c": 1 }); // { a: { b: { c: 1 } } }
146
+ ```
147
+
148
+ ### `obj.keys<T>(obj): (keyof T)[]`
149
+
150
+ Type-safe `Object.keys`.
151
+
152
+ ### `obj.entries<T>(obj): [keyof T, T[keyof T]][]`
153
+
154
+ Type-safe `Object.entries`.
155
+
156
+ ### `obj.fromEntries<T>(entries): object`
157
+
158
+ Type-safe `Object.fromEntries`.
159
+
160
+ ### `obj.map<S, K, V>(obj, fn): Record<K, V>`
161
+
162
+ Transform each entry of an object. The `fn` receives `(key, value)` and returns `[newKey | null, newValue]`. If `newKey` is `null`, the original key is preserved.
163
+
164
+ ```typescript
165
+ obj.map({ a: 1, b: 2 }, (k, v) => [null, v * 10]);
166
+ // { a: 10, b: 20 }
167
+ ```
168
+
169
+ ### Type Utilities (from `obj`)
170
+
171
+ #### `UndefToOptional<T>`
172
+
173
+ Converts properties that include `undefined` in their type to optional properties.
174
+
175
+ ```typescript
176
+ type UndefToOptional<T> = { [K in ...]?: T[K] } & { [K in ...]: T[K] };
177
+ ```
178
+
179
+ #### `OptionalToUndef<T>`
180
+
181
+ Converts optional properties to required properties with `| undefined`.
182
+
183
+ ```typescript
184
+ type OptionalToUndef<T> = { [K in keyof T]-?: ... };
185
+ ```
186
+
187
+ ## `str` -- String Utilities
188
+
189
+ ### `str.getKoreanSuffix(text, type): string`
190
+
191
+ Returns the appropriate Korean suffix based on whether the last character has a final consonant.
192
+
193
+ ```typescript
194
+ function getKoreanSuffix(text: string, type: "을" | "은" | "이" | "와" | "랑" | "로" | "라"): string;
195
+ ```
196
+
197
+ | Type | With final consonant | Without |
198
+ |------|---------------------|---------|
199
+ | `"을"` | 을 | 를 |
200
+ | `"은"` | 은 | 는 |
201
+ | `"이"` | 이 | 가 |
202
+ | `"와"` | 과 | 와 |
203
+ | `"랑"` | 이랑 | 랑 |
204
+ | `"로"` | 으로 | 로 |
205
+ | `"라"` | 이라 | 라 |
206
+
207
+ ### `str.replaceFullWidth(str): string`
208
+
209
+ Converts full-width characters to half-width (A-Z, a-z, 0-9, space, parentheses).
210
+
211
+ ```typescript
212
+ str.replaceFullWidth("A123"); // "A123"
213
+ ```
214
+
215
+ ### `str.toPascalCase(str): string`
216
+
217
+ Converts to PascalCase. Handles `-`, `_`, `.` separators.
218
+
219
+ ```typescript
220
+ str.toPascalCase("hello-world"); // "HelloWorld"
221
+ ```
222
+
223
+ ### `str.toCamelCase(str): string`
224
+
225
+ Converts to camelCase.
226
+
227
+ ```typescript
228
+ str.toCamelCase("hello-world"); // "helloWorld"
229
+ ```
230
+
231
+ ### `str.toKebabCase(str): string`
232
+
233
+ Converts to kebab-case from PascalCase/camelCase.
234
+
235
+ ```typescript
236
+ str.toKebabCase("HelloWorld"); // "hello-world"
237
+ ```
238
+
239
+ ### `str.toSnakeCase(str): string`
240
+
241
+ Converts to snake_case from PascalCase/camelCase.
242
+
243
+ ```typescript
244
+ str.toSnakeCase("HelloWorld"); // "hello_world"
245
+ ```
246
+
247
+ ### `str.isNullOrEmpty(str): str is "" | undefined`
248
+
249
+ Type guard that returns `true` if the string is `undefined`, `null`, or `""`.
250
+
251
+ ```typescript
252
+ if (!str.isNullOrEmpty(name)) {
253
+ // name is guaranteed to be a non-empty string
254
+ }
255
+ ```
256
+
257
+ ### `str.insert(str, index, insertString): string`
258
+
259
+ Inserts a string at the given position.
260
+
261
+ ```typescript
262
+ str.insert("Hello World", 5, ","); // "Hello, World"
263
+ ```
264
+
265
+ ## `num` -- Number Utilities
266
+
267
+ ### `num.parseInt(text): number | undefined`
268
+
269
+ Parses a string to integer. Strips non-numeric characters first (keeps `0-9`, `-`, `.`). Returns `undefined` if unparseable.
270
+
271
+ ### `num.parseFloat(text): number | undefined`
272
+
273
+ Parses a string to float. Strips non-numeric characters first.
274
+
275
+ ### `num.parseRoundedInt(text): number | undefined`
276
+
277
+ Parses to float then rounds to nearest integer.
278
+
279
+ ### `num.isNullOrEmpty(val): val is 0 | undefined`
280
+
281
+ Type guard that returns `true` if the value is `undefined`, `null`, or `0`.
282
+
283
+ ### `num.format(val, digit?): string | undefined`
284
+
285
+ Formats a number with thousands separators and optional decimal control.
286
+
287
+ ```typescript
288
+ function format(val: number, digit?: { max?: number; min?: number }): string;
289
+ function format(val: number | undefined, digit?: { max?: number; min?: number }): string | undefined;
290
+ ```
291
+
292
+ ```typescript
293
+ num.format(1234.567, { max: 2 }); // "1,234.57"
294
+ num.format(1234, { min: 2 }); // "1,234.00"
295
+ ```
296
+
297
+ ## `bytes` -- Uint8Array Utilities
298
+
299
+ ### `bytes.concat(arrays): Bytes`
300
+
301
+ Concatenates multiple `Uint8Array` instances into one.
302
+
303
+ ### `bytes.toHex(bytes): string`
304
+
305
+ Converts to lowercase hex string.
306
+
307
+ ### `bytes.fromHex(hex): Bytes`
308
+
309
+ Converts hex string to `Uint8Array`. Throws `ArgumentError` on invalid input.
310
+
311
+ ### `bytes.toBase64(bytes): string`
312
+
313
+ Converts to base64 string.
314
+
315
+ ### `bytes.fromBase64(base64): Bytes`
316
+
317
+ Converts base64 string to `Uint8Array`. Throws `ArgumentError` on invalid input.
318
+
319
+ ```typescript
320
+ const a = new Uint8Array([1, 2]);
321
+ const b = new Uint8Array([3, 4]);
322
+ bytes.concat([a, b]); // Uint8Array([1, 2, 3, 4])
323
+ bytes.toHex(a); // "0102"
324
+ bytes.toBase64(a); // "AQI="
325
+ bytes.fromHex("ff00"); // Uint8Array([255, 0])
326
+ bytes.fromBase64("SGVsbG8="); // Uint8Array([72, 101, 108, 108, 111])
327
+ ```
328
+
329
+ ## `path` -- Path Utilities
330
+
331
+ POSIX-style path utilities (forward slash only). Designed for browser and Capacitor environments. Does not support Windows backslash paths.
332
+
333
+ ### `path.join(...segments): string`
334
+
335
+ Joins path segments with `/`.
336
+
337
+ ### `path.basename(filePath, ext?): string`
338
+
339
+ Extracts the file name from a path. Optionally strips the extension.
340
+
341
+ ### `path.extname(filePath): string`
342
+
343
+ Extracts the file extension (including the dot). Hidden files (e.g., `.gitignore`) return `""`.
344
+
345
+ ```typescript
346
+ path.join("a", "b", "c.txt"); // "a/b/c.txt"
347
+ path.basename("/dir/file.txt"); // "file.txt"
348
+ path.basename("/dir/file.txt", ".txt"); // "file"
349
+ path.extname("/dir/file.txt"); // ".txt"
350
+ ```
351
+
352
+ ## `json` -- JSON Utilities
353
+
354
+ JSON stringify/parse with support for custom types: DateTime, DateOnly, Time, Uuid, Set, Map, Error, Uint8Array, Date.
355
+
356
+ ### `json.stringify(obj, options?): string`
357
+
358
+ ```typescript
359
+ function stringify(obj: unknown, options?: {
360
+ space?: string | number;
361
+ replacer?: (key: string | undefined, value: unknown) => unknown;
362
+ redactBytes?: boolean;
363
+ }): string;
364
+ ```
365
+
366
+ | Option | Description |
367
+ |--------|-------------|
368
+ | `space` | Indentation (number of spaces or string) |
369
+ | `replacer` | Custom replacer called before built-in type conversion |
370
+ | `redactBytes` | If `true`, replaces `Uint8Array` content with `"__hidden__"` (for logging) |
371
+
372
+ Custom types are serialized as `{ __type__: "TypeName", data: ... }`. Circular references throw `TypeError`.
373
+
374
+ ### `json.parse<T>(json): T`
375
+
376
+ Restores custom types from `__type__` markers. All JSON `null` values are converted to `undefined` (simplysm null-free convention).
377
+
378
+ ```typescript
379
+ const data = json.parse<MyType>(jsonString);
380
+ ```
381
+
382
+ ## `xml` -- XML Utilities
383
+
384
+ Built on `fast-xml-parser`.
385
+
386
+ ### `xml.parse(str, options?): unknown`
387
+
388
+ Parses XML string to an object. Attributes are grouped under `$`, text nodes under `_`, child elements as arrays.
389
+
390
+ ```typescript
391
+ function parse(str: string, options?: { stripTagPrefix?: boolean }): unknown;
392
+ ```
393
+
394
+ | Option | Description |
395
+ |--------|-------------|
396
+ | `stripTagPrefix` | Remove namespace prefixes from tag names |
397
+
398
+ ```typescript
399
+ xml.parse('<root id="1"><item>hello</item></root>');
400
+ // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
401
+ ```
402
+
403
+ ### `xml.stringify(obj, options?): string`
404
+
405
+ Converts an object to XML string.
406
+
407
+ ```typescript
408
+ function stringify(obj: unknown, options?: XmlBuilderOptions): string;
409
+ ```
410
+
411
+ ## `wait` -- Wait Utilities
412
+
413
+ ### `wait.until(forwarder, milliseconds?, maxCount?): Promise<void>`
414
+
415
+ Polls a condition function until it returns `true`.
416
+
417
+ ```typescript
418
+ function until(
419
+ forwarder: () => boolean | Promise<boolean>,
420
+ milliseconds?: number, // default: 100ms
421
+ maxCount?: number, // default: unlimited
422
+ ): Promise<void>;
423
+ ```
424
+
425
+ Throws `TimeoutError` if `maxCount` is reached.
426
+
427
+ ### `wait.time(millisecond): Promise<void>`
428
+
429
+ Delays for the specified number of milliseconds.
430
+
431
+ ```typescript
432
+ await wait.time(1000); // wait 1 second
433
+ ```
434
+
435
+ ## `transfer` -- Transferable Utilities
436
+
437
+ Encode/decode objects for Worker `postMessage` with zero-copy `ArrayBuffer` transfer. Handles custom types that `structuredClone` does not support.
438
+
439
+ ### `transfer.encode(obj): { result, transferList }`
440
+
441
+ Encodes an object for Worker transfer. Custom types become tagged objects. `Uint8Array` buffers are added to `transferList` for zero-copy transfer.
442
+
443
+ ```typescript
444
+ function encode(obj: unknown): {
445
+ result: unknown;
446
+ transferList: ArrayBuffer[];
447
+ };
448
+ ```
449
+
450
+ Throws `TypeError` on circular references (with path info).
451
+
452
+ Supported types: Date, DateTime, DateOnly, Time, Uuid, RegExp, Error, Uint8Array, Array, Map, Set, plain objects.
453
+
454
+ ### `transfer.decode(obj): unknown`
455
+
456
+ Decodes a previously encoded object, restoring custom types.
457
+
458
+ ```typescript
459
+ function decode(obj: unknown): unknown;
460
+ ```
461
+
462
+ ```typescript
463
+ // Sending
464
+ const { result, transferList } = transfer.encode(data);
465
+ worker.postMessage(result, transferList);
466
+
467
+ // Receiving
468
+ const decoded = transfer.decode(event.data);
469
+ ```
470
+
471
+ ## `err` -- Error Utilities
472
+
473
+ ### `err.message(err): string`
474
+
475
+ Extracts a message string from an `unknown` error value.
476
+
477
+ ```typescript
478
+ function message(err: unknown): string;
479
+ ```
480
+
481
+ Returns `err.message` if `err` is an `Error`, otherwise `String(err)`.
482
+
483
+ ## `dt` -- Date Format Utilities
484
+
485
+ ### `dt.format(formatString, args): string`
486
+
487
+ Formats date/time components using C#-style format strings.
488
+
489
+ ```typescript
490
+ function format(formatString: string, args: {
491
+ year?: number;
492
+ month?: number;
493
+ day?: number;
494
+ hour?: number;
495
+ minute?: number;
496
+ second?: number;
497
+ millisecond?: number;
498
+ timezoneOffsetMinutes?: number;
499
+ }): string;
500
+ ```
501
+
502
+ **Format patterns:**
503
+
504
+ | Pattern | Description | Example |
505
+ |---------|-------------|---------|
506
+ | `yyyy` | 4-digit year | 2024 |
507
+ | `yy` | 2-digit year | 24 |
508
+ | `MM` | Zero-padded month | 01-12 |
509
+ | `M` | Month | 1-12 |
510
+ | `ddd` | Day of week (Korean) | 일, 월, 화, 수, 목, 금, 토 |
511
+ | `dd` | Zero-padded day | 01-31 |
512
+ | `d` | Day | 1-31 |
513
+ | `tt` | AM/PM | AM, PM |
514
+ | `hh` | Zero-padded 12-hour | 01-12 |
515
+ | `h` | 12-hour | 1-12 |
516
+ | `HH` | Zero-padded 24-hour | 00-23 |
517
+ | `H` | 24-hour | 0-23 |
518
+ | `mm` | Zero-padded minutes | 00-59 |
519
+ | `m` | Minutes | 0-59 |
520
+ | `ss` | Zero-padded seconds | 00-59 |
521
+ | `s` | Seconds | 0-59 |
522
+ | `fff` | Milliseconds (3 digits) | 000-999 |
523
+ | `ff` | Milliseconds (2 digits) | 00-99 |
524
+ | `f` | Milliseconds (1 digit) | 0-9 |
525
+ | `zzz` | Timezone offset | +09:00 |
526
+ | `zz` | Timezone offset (hours) | +09 |
527
+ | `z` | Timezone offset (short) | +9 |
528
+
529
+ ### `dt.normalizeMonth(year, month, day): DtNormalizedMonth`
530
+
531
+ Normalizes month overflow/underflow and adjusts day to fit the target month.
532
+
533
+ ```typescript
534
+ dt.normalizeMonth(2025, 13, 15); // { year: 2026, month: 1, day: 15 }
535
+ dt.normalizeMonth(2025, 2, 31); // { year: 2025, month: 2, day: 28 }
536
+ ```
537
+
538
+ ### `dt.convert12To24(rawHour, isPM): number`
539
+
540
+ Converts 12-hour format to 24-hour format.
541
+
542
+ ## `primitive` -- Primitive Type Utilities
543
+
544
+ ### `primitive.typeStr(value): PrimitiveTypeStr`
545
+
546
+ Returns the `PrimitiveTypeStr` for a given value at runtime.
547
+
548
+ ```typescript
549
+ function typeStr(value: PrimitiveTypeMap[PrimitiveTypeStr]): PrimitiveTypeStr;
550
+ ```
551
+
552
+ ```typescript
553
+ primitive.typeStr("hello"); // "string"
554
+ primitive.typeStr(123); // "number"
555
+ primitive.typeStr(true); // "boolean"
556
+ primitive.typeStr(new DateTime()); // "DateTime"
557
+ primitive.typeStr(new Uint8Array()); // "Bytes"
558
+ ```
559
+
560
+ Throws `ArgumentError` for unsupported types.
561
+
562
+ ## Template String Tags
563
+
564
+ Template tag functions for IDE syntax highlighting. All perform string interpolation + indent normalization (strips common leading whitespace).
565
+
566
+ ### `js`, `ts`, `html`, `tsql`, `mysql`, `pgsql`
567
+
568
+ ```typescript
569
+ function js(strings: TemplateStringsArray, ...values: unknown[]): string;
570
+ function ts(strings: TemplateStringsArray, ...values: unknown[]): string;
571
+ function html(strings: TemplateStringsArray, ...values: unknown[]): string;
572
+ function tsql(strings: TemplateStringsArray, ...values: unknown[]): string;
573
+ function mysql(strings: TemplateStringsArray, ...values: unknown[]): string;
574
+ function pgsql(strings: TemplateStringsArray, ...values: unknown[]): string;
575
+ ```
576
+
577
+ ```typescript
578
+ const code = ts`
579
+ interface User {
580
+ name: string;
581
+ age: number;
582
+ }
583
+ `;
584
+ // Result: "interface User {\n name: string;\n age: number;\n}"
585
+ ```
586
+
587
+ ## `ZipArchive`
588
+
589
+ ZIP file read/write/compress/extract. Supports `await using` syntax (`Symbol.asyncDispose`).
590
+
591
+ ```typescript
592
+ class ZipArchive {
593
+ constructor(data?: Blob | Bytes);
594
+
595
+ async get(fileName: string): Promise<Bytes | undefined>;
596
+ async exists(fileName: string): Promise<boolean>;
597
+ write(fileName: string, bytes: Bytes): void;
598
+ async extractAll(progressCallback?: (progress: ZipArchiveProgress) => void): Promise<Map<string, Bytes | undefined>>;
599
+ async compress(): Promise<Bytes>;
600
+ async close(): Promise<void>;
601
+ async [Symbol.asyncDispose](): Promise<void>;
602
+ }
603
+ ```
604
+
605
+ ### `ZipArchiveProgress`
606
+
607
+ ```typescript
608
+ interface ZipArchiveProgress {
609
+ fileName: string;
610
+ totalSize: number;
611
+ extractedSize: number;
612
+ }
613
+ ```
614
+
615
+ ### Methods
616
+
617
+ | Method | Description |
618
+ |--------|-------------|
619
+ | `get(fileName)` | Extract a single file. Cached after first extraction |
620
+ | `exists(fileName)` | Check if a file exists in the archive |
621
+ | `write(fileName, bytes)` | Write a file to the cache (for compression) |
622
+ | `extractAll(callback?)` | Extract all files with optional progress reporting |
623
+ | `compress()` | Compress all cached files into a ZIP `Uint8Array` |
624
+ | `close()` | Close the reader and clear cache |
625
+
626
+ ```typescript
627
+ // Reading a ZIP
628
+ await using archive = new ZipArchive(zipBytes);
629
+ const content = await archive.get("file.txt");
630
+
631
+ // Creating a ZIP
632
+ await using archive = new ZipArchive();
633
+ archive.write("file.txt", textBytes);
634
+ archive.write("data.json", jsonBytes);
635
+ const zipBytes = await archive.compress();
636
+
637
+ // Extracting all with progress
638
+ const files = await archive.extractAll((p) => {
639
+ console.log(`${p.fileName}: ${p.extractedSize}/${p.totalSize}`);
640
+ });
641
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/core-common",
3
- "version": "14.0.1",
3
+ "version": "14.0.4",
4
4
  "description": "심플리즘 패키지 - 코어 (common)",
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": [
20
21
  "./src/extensions/arr-ext.ts",
@@ -26,6 +27,9 @@
26
27
  "./dist/extensions/set-ext.js",
27
28
  "./dist/index.js"
28
29
  ],
30
+ "devDependencies": {
31
+ "@types/node": "^20.19.37"
32
+ },
29
33
  "dependencies": {
30
34
  "@zip.js/zip.js": "^2.8.23",
31
35
  "consola": "^3.4.2",
package/src/env.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  declare const process: { env: { DEV?: string; VER?: string; [key: string]: string | undefined } };
2
2
 
3
3
  declare global {
4
+ interface ImportMetaEnv extends Record<string, unknown> {}
4
5
  interface ImportMeta {
5
- env?: Record<string, unknown>;
6
+ readonly env: ImportMetaEnv;
6
7
  }
7
8
  }
8
9
 
@@ -14,7 +15,7 @@ export function parseBoolEnv(value: unknown): boolean {
14
15
  return ["true", "1", "yes", "on"].includes(String(value ?? "").toLowerCase());
15
16
  }
16
17
 
17
- const _metaEnv: Record<string, unknown> = import.meta.env ?? {};
18
+ const _metaEnv: Record<string, unknown> = { ...import.meta.env };
18
19
  const _processEnv: Record<string, unknown> = typeof process !== "undefined" ? process.env : {};
19
20
  const _raw: Record<string, unknown> = { ..._metaEnv, ..._processEnv };
20
21