@simplysm/core-common 13.0.69 → 13.0.71
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/README.md +66 -267
- package/dist/common.types.d.ts +14 -14
- package/dist/errors/argument-error.d.ts +10 -10
- package/dist/errors/argument-error.d.ts.map +1 -1
- package/dist/errors/argument-error.js +2 -2
- package/dist/errors/argument-error.js.map +1 -1
- package/dist/errors/not-implemented-error.d.ts +8 -8
- package/dist/errors/not-implemented-error.js +2 -2
- package/dist/errors/not-implemented-error.js.map +1 -1
- package/dist/errors/sd-error.d.ts +10 -10
- package/dist/errors/sd-error.d.ts.map +1 -1
- package/dist/errors/timeout-error.d.ts +10 -10
- package/dist/errors/timeout-error.js +3 -3
- package/dist/errors/timeout-error.js.map +1 -1
- package/dist/extensions/arr-ext.d.ts +2 -2
- package/dist/extensions/arr-ext.helpers.d.ts +8 -8
- 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 +13 -13
- package/dist/extensions/arr-ext.js.map +1 -1
- package/dist/extensions/arr-ext.types.d.ts +57 -57
- package/dist/extensions/arr-ext.types.d.ts.map +1 -1
- package/dist/extensions/map-ext.d.ts +16 -16
- package/dist/extensions/set-ext.d.ts +11 -11
- package/dist/features/debounce-queue.d.ts +17 -15
- package/dist/features/debounce-queue.d.ts.map +1 -1
- package/dist/features/debounce-queue.js +6 -6
- package/dist/features/debounce-queue.js.map +1 -1
- package/dist/features/event-emitter.d.ts +20 -20
- package/dist/features/event-emitter.js +17 -17
- package/dist/features/serial-queue.d.ts +11 -11
- package/dist/features/serial-queue.js +5 -5
- package/dist/features/serial-queue.js.map +1 -1
- package/dist/globals.d.ts +4 -4
- package/dist/types/date-only.d.ts +64 -64
- package/dist/types/date-only.d.ts.map +1 -1
- package/dist/types/date-only.js +63 -63
- package/dist/types/date-time.d.ts +37 -37
- package/dist/types/date-time.d.ts.map +1 -1
- package/dist/types/date-time.js +54 -37
- package/dist/types/date-time.js.map +1 -1
- package/dist/types/lazy-gc-map.d.ts +26 -26
- package/dist/types/lazy-gc-map.d.ts.map +1 -1
- package/dist/types/lazy-gc-map.js +26 -26
- package/dist/types/lazy-gc-map.js.map +1 -1
- package/dist/types/time.d.ts +25 -25
- package/dist/types/time.d.ts.map +1 -1
- package/dist/types/time.js +25 -25
- package/dist/types/time.js.map +1 -1
- package/dist/types/uuid.d.ts +11 -11
- package/dist/types/uuid.d.ts.map +1 -1
- package/dist/types/uuid.js +12 -12
- package/dist/types/uuid.js.map +1 -1
- package/dist/utils/bytes.d.ts +17 -17
- package/dist/utils/bytes.js +4 -4
- package/dist/utils/bytes.js.map +1 -1
- package/dist/utils/date-format.d.ts +45 -45
- package/dist/utils/date-format.js +1 -1
- package/dist/utils/date-format.js.map +1 -1
- package/dist/utils/error.d.ts +4 -4
- package/dist/utils/json.d.ts +17 -17
- package/dist/utils/json.js +3 -3
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/num.d.ts +23 -23
- package/dist/utils/obj.d.ts +111 -111
- package/dist/utils/obj.d.ts.map +1 -1
- package/dist/utils/obj.js +3 -3
- package/dist/utils/obj.js.map +1 -1
- package/dist/utils/path.d.ts +10 -10
- package/dist/utils/primitive.d.ts +5 -5
- package/dist/utils/primitive.js +1 -1
- package/dist/utils/primitive.js.map +1 -1
- package/dist/utils/str.d.ts +46 -46
- package/dist/utils/str.d.ts.map +1 -1
- package/dist/utils/str.js +5 -5
- package/dist/utils/str.js.map +1 -1
- package/dist/utils/template-strings.d.ts +26 -26
- package/dist/utils/transferable.d.ts +18 -18
- package/dist/utils/transferable.js +1 -1
- package/dist/utils/transferable.js.map +1 -1
- package/dist/utils/wait.d.ts +9 -9
- package/dist/utils/xml.d.ts +13 -13
- package/dist/utils/xml.d.ts.map +1 -1
- package/dist/utils/xml.js +1 -0
- package/dist/utils/xml.js.map +1 -1
- package/dist/zip/sd-zip.d.ts +22 -22
- package/dist/zip/sd-zip.js +16 -16
- package/package.json +4 -4
- package/src/common.types.ts +17 -17
- package/src/errors/argument-error.ts +15 -15
- package/src/errors/not-implemented-error.ts +9 -9
- package/src/errors/sd-error.ts +12 -12
- package/src/errors/timeout-error.ts +12 -12
- package/src/extensions/arr-ext.helpers.ts +10 -10
- package/src/extensions/arr-ext.ts +57 -57
- package/src/extensions/arr-ext.types.ts +59 -59
- package/src/extensions/map-ext.ts +16 -16
- package/src/extensions/set-ext.ts +11 -11
- package/src/features/debounce-queue.ts +21 -19
- package/src/features/event-emitter.ts +25 -25
- package/src/features/serial-queue.ts +13 -13
- package/src/globals.ts +4 -4
- package/src/index.ts +1 -1
- package/src/types/date-only.ts +83 -83
- package/src/types/date-time.ts +64 -44
- package/src/types/lazy-gc-map.ts +45 -45
- package/src/types/time.ts +34 -34
- package/src/types/uuid.ts +17 -17
- package/src/utils/bytes.ts +35 -35
- package/src/utils/date-format.ts +65 -65
- package/src/utils/error.ts +4 -4
- package/src/utils/json.ts +39 -39
- package/src/utils/num.ts +23 -23
- package/src/utils/obj.ts +138 -138
- package/src/utils/path.ts +10 -10
- package/src/utils/primitive.ts +6 -6
- package/src/utils/str.ts +260 -261
- package/src/utils/template-strings.ts +29 -29
- package/src/utils/transferable.ts +284 -284
- package/src/utils/wait.ts +10 -10
- package/src/utils/xml.ts +20 -19
- package/src/zip/sd-zip.ts +25 -25
- package/tests/errors/errors.spec.ts +80 -0
- package/tests/extensions/array-extension.spec.ts +796 -0
- package/tests/extensions/map-extension.spec.ts +147 -0
- package/tests/extensions/set-extension.spec.ts +74 -0
- package/tests/types/date-only.spec.ts +638 -0
- package/tests/types/date-time.spec.ts +391 -0
- package/tests/types/lazy-gc-map.spec.ts +692 -0
- package/tests/types/time.spec.ts +559 -0
- package/tests/types/uuid.spec.ts +74 -0
- package/tests/utils/bytes-utils.spec.ts +230 -0
- package/tests/utils/date-format.spec.ts +373 -0
- package/tests/utils/debounce-queue.spec.ts +272 -0
- package/tests/utils/json.spec.ts +486 -0
- package/tests/utils/number.spec.ts +157 -0
- package/tests/utils/object.spec.ts +829 -0
- package/tests/utils/path.spec.ts +78 -0
- package/tests/utils/primitive.spec.ts +43 -0
- package/tests/utils/sd-event-emitter.spec.ts +216 -0
- package/tests/utils/serial-queue.spec.ts +365 -0
- package/tests/utils/string.spec.ts +281 -0
- package/tests/utils/template-strings.spec.ts +57 -0
- package/tests/utils/transferable.spec.ts +703 -0
- package/tests/utils/wait.spec.ts +145 -0
- package/tests/utils/xml.spec.ts +146 -0
- package/tests/zip/sd-zip.spec.ts +238 -0
- package/docs/extensions.md +0 -503
- package/docs/features.md +0 -109
- package/docs/types.md +0 -486
- package/docs/utils.md +0 -780
package/src/utils/xml.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* XML
|
|
2
|
+
* XML conversion utility
|
|
3
3
|
*/
|
|
4
4
|
import type { XmlBuilderOptions } from "fast-xml-parser";
|
|
5
5
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
@@ -7,14 +7,14 @@ import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
|
7
7
|
//#region parse
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* XML
|
|
11
|
-
* @param str XML
|
|
12
|
-
* @param options
|
|
13
|
-
* @param options.stripTagPrefix
|
|
14
|
-
* @returns
|
|
15
|
-
* -
|
|
16
|
-
* -
|
|
17
|
-
* -
|
|
10
|
+
* Parse XML string into an object
|
|
11
|
+
* @param str XML string
|
|
12
|
+
* @param options Options
|
|
13
|
+
* @param options.stripTagPrefix Whether to remove tag prefix (namespace)
|
|
14
|
+
* @returns Parsed object. Structure:
|
|
15
|
+
* - Attributes: grouped in `$` object
|
|
16
|
+
* - Text nodes: stored in `_` key
|
|
17
|
+
* - Child elements: converted to array (except root element)
|
|
18
18
|
* @example
|
|
19
19
|
* xmlParse('<root id="1"><item>hello</item></root>');
|
|
20
20
|
* // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
|
|
@@ -27,6 +27,7 @@ export function xmlParse(str: string, options?: { stripTagPrefix?: boolean }): u
|
|
|
27
27
|
parseAttributeValue: false,
|
|
28
28
|
parseTagValue: false,
|
|
29
29
|
textNodeName: "_",
|
|
30
|
+
htmlEntities: true,
|
|
30
31
|
isArray: (_tagName: string, jPath: string, _isLeafNode: boolean, isAttribute: boolean) => {
|
|
31
32
|
return !isAttribute && jPath.split(".").length > 1;
|
|
32
33
|
},
|
|
@@ -39,10 +40,10 @@ export function xmlParse(str: string, options?: { stripTagPrefix?: boolean }): u
|
|
|
39
40
|
//#region stringify
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
|
-
*
|
|
43
|
-
* @param obj
|
|
44
|
-
* @param options fast-xml-parser XmlBuilderOptions (
|
|
45
|
-
* @returns XML
|
|
43
|
+
* Serialize object to XML string
|
|
44
|
+
* @param obj Object to serialize
|
|
45
|
+
* @param options fast-xml-parser XmlBuilderOptions (optional)
|
|
46
|
+
* @returns XML string
|
|
46
47
|
* @example
|
|
47
48
|
* xmlStringify({
|
|
48
49
|
* root: {
|
|
@@ -68,10 +69,10 @@ export function xmlStringify(obj: unknown, options?: XmlBuilderOptions): string
|
|
|
68
69
|
//#region private
|
|
69
70
|
|
|
70
71
|
/**
|
|
71
|
-
*
|
|
72
|
-
* @note
|
|
73
|
-
*
|
|
74
|
-
*
|
|
72
|
+
* Remove namespace prefix from tag name
|
|
73
|
+
* @note Removes the namespace prefix in the format "ns:tag" from XML parsing results, leaving only the tag name.
|
|
74
|
+
* This allows consistent access to XML data without considering namespace.
|
|
75
|
+
* However, attributes are kept with their prefix.
|
|
75
76
|
*/
|
|
76
77
|
function stripTagPrefix(obj: unknown): unknown {
|
|
77
78
|
if (Array.isArray(obj)) {
|
|
@@ -85,11 +86,11 @@ function stripTagPrefix(obj: unknown): unknown {
|
|
|
85
86
|
for (const key of Object.keys(record)) {
|
|
86
87
|
const value = record[key];
|
|
87
88
|
|
|
88
|
-
//
|
|
89
|
+
// Attributes must not have prefix removed
|
|
89
90
|
if (key === "$") {
|
|
90
91
|
newObj[key] = value;
|
|
91
92
|
} else {
|
|
92
|
-
//
|
|
93
|
+
// Remove prefix from tag names only, based on first ":"
|
|
93
94
|
const colonIndex = key.indexOf(":");
|
|
94
95
|
const cleanKey = colonIndex !== -1 ? key.slice(colonIndex + 1) : key;
|
|
95
96
|
newObj[cleanKey] = stripTagPrefix(value);
|
package/src/zip/sd-zip.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ZIP
|
|
2
|
+
* ZIP file processing utility
|
|
3
3
|
*/
|
|
4
4
|
import type { FileEntry } from "@zip.js/zip.js";
|
|
5
5
|
import {
|
|
@@ -18,25 +18,25 @@ export interface ZipArchiveProgress {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* ZIP
|
|
21
|
+
* ZIP archive processing class
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Handles reading, writing, compression, and decompression of ZIP files.
|
|
24
|
+
* Uses internal caching to prevent duplicate decompression of the same file.
|
|
25
25
|
*
|
|
26
26
|
* @example
|
|
27
|
-
* // ZIP
|
|
27
|
+
* // Read ZIP file
|
|
28
28
|
* await using archive = new ZipArchive(zipBytes);
|
|
29
29
|
* const content = await archive.get("file.txt");
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
|
-
* // ZIP
|
|
32
|
+
* // Create ZIP file
|
|
33
33
|
* await using archive = new ZipArchive();
|
|
34
34
|
* archive.write("file.txt", textBytes);
|
|
35
35
|
* archive.write("data.json", jsonBytes);
|
|
36
36
|
* const zipBytes = await archive.compress();
|
|
37
37
|
*
|
|
38
38
|
* @example
|
|
39
|
-
* //
|
|
39
|
+
* // Extract all files (with progress reporting)
|
|
40
40
|
* await using archive = new ZipArchive(zipBytes);
|
|
41
41
|
* const files = await archive.extractAll((progress) => {
|
|
42
42
|
* console.log(`${progress.fileName}: ${progress.extractedSize}/${progress.totalSize}`);
|
|
@@ -48,8 +48,8 @@ export class ZipArchive {
|
|
|
48
48
|
private _entries?: Awaited<ReturnType<ZipReader<Blob | Bytes>["getEntries"]>>;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* ZipArchive
|
|
52
|
-
* @param data ZIP
|
|
51
|
+
* Create ZipArchive
|
|
52
|
+
* @param data ZIP data (omit to create a new archive)
|
|
53
53
|
*/
|
|
54
54
|
constructor(data?: Blob | Bytes) {
|
|
55
55
|
if (!data) return;
|
|
@@ -70,8 +70,8 @@ export class ZipArchive {
|
|
|
70
70
|
|
|
71
71
|
//#region extractAll
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
74
|
-
* @param progressCallback
|
|
73
|
+
* Extract all files
|
|
74
|
+
* @param progressCallback Progress callback
|
|
75
75
|
*/
|
|
76
76
|
async extractAll(
|
|
77
77
|
progressCallback?: (progress: ZipArchiveProgress) => void,
|
|
@@ -79,7 +79,7 @@ export class ZipArchive {
|
|
|
79
79
|
const entries = await this._getEntries();
|
|
80
80
|
if (entries == null) return this._cache;
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// Calculate total size to extract
|
|
83
83
|
const totalSize = entries
|
|
84
84
|
.filter((e) => !e.directory)
|
|
85
85
|
.reduce((acc, e) => acc + e.uncompressedSize, 0);
|
|
@@ -112,7 +112,7 @@ export class ZipArchive {
|
|
|
112
112
|
|
|
113
113
|
this._cache.set(entry.filename, entryBytes);
|
|
114
114
|
|
|
115
|
-
//
|
|
115
|
+
// Accumulate when individual file completes
|
|
116
116
|
totalExtracted += entry.uncompressedSize;
|
|
117
117
|
|
|
118
118
|
progressCallback?.({
|
|
@@ -128,8 +128,8 @@ export class ZipArchive {
|
|
|
128
128
|
|
|
129
129
|
//#region get
|
|
130
130
|
/**
|
|
131
|
-
*
|
|
132
|
-
* @param fileName
|
|
131
|
+
* Extract specific file
|
|
132
|
+
* @param fileName File name
|
|
133
133
|
*/
|
|
134
134
|
async get(fileName: string): Promise<Bytes | undefined> {
|
|
135
135
|
if (this._cache.has(fileName)) {
|
|
@@ -156,8 +156,8 @@ export class ZipArchive {
|
|
|
156
156
|
|
|
157
157
|
//#region exists
|
|
158
158
|
/**
|
|
159
|
-
*
|
|
160
|
-
* @param fileName
|
|
159
|
+
* Check if file exists
|
|
160
|
+
* @param fileName File name
|
|
161
161
|
*/
|
|
162
162
|
async exists(fileName: string): Promise<boolean> {
|
|
163
163
|
if (this._cache.has(fileName)) {
|
|
@@ -176,9 +176,9 @@ export class ZipArchive {
|
|
|
176
176
|
|
|
177
177
|
//#region write
|
|
178
178
|
/**
|
|
179
|
-
*
|
|
180
|
-
* @param fileName
|
|
181
|
-
* @param bytes
|
|
179
|
+
* Write file (store in cache)
|
|
180
|
+
* @param fileName File name
|
|
181
|
+
* @param bytes File content
|
|
182
182
|
*/
|
|
183
183
|
write(fileName: string, bytes: Bytes): void {
|
|
184
184
|
this._cache.set(fileName, bytes);
|
|
@@ -187,11 +187,11 @@ export class ZipArchive {
|
|
|
187
187
|
|
|
188
188
|
//#region compress
|
|
189
189
|
/**
|
|
190
|
-
*
|
|
190
|
+
* Compress cached files to ZIP
|
|
191
191
|
*
|
|
192
192
|
* @remarks
|
|
193
|
-
*
|
|
194
|
-
*
|
|
193
|
+
* Internally calls `extractAll()` to load all files into memory before compressing.
|
|
194
|
+
* Be mindful of memory usage when dealing with large ZIP files.
|
|
195
195
|
*/
|
|
196
196
|
async compress(): Promise<Bytes> {
|
|
197
197
|
const fileMap = await this.extractAll();
|
|
@@ -211,7 +211,7 @@ export class ZipArchive {
|
|
|
211
211
|
|
|
212
212
|
//#region close
|
|
213
213
|
/**
|
|
214
|
-
*
|
|
214
|
+
* Close reader and clear cache
|
|
215
215
|
*/
|
|
216
216
|
async close(): Promise<void> {
|
|
217
217
|
await this._reader?.close();
|
|
@@ -219,7 +219,7 @@ export class ZipArchive {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
/**
|
|
222
|
-
* await using
|
|
222
|
+
* Support for await using
|
|
223
223
|
*/
|
|
224
224
|
async [Symbol.asyncDispose](): Promise<void> {
|
|
225
225
|
await this.close();
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { SdError, ArgumentError } from "@simplysm/core-common";
|
|
3
|
+
|
|
4
|
+
describe("Errors", () => {
|
|
5
|
+
//#region SdError
|
|
6
|
+
|
|
7
|
+
describe("SdError", () => {
|
|
8
|
+
it("Creates with cause", () => {
|
|
9
|
+
const cause = new Error("original error");
|
|
10
|
+
const error = new SdError(cause, "wrapped message");
|
|
11
|
+
|
|
12
|
+
// Message combined as "wrapped message => original error" format
|
|
13
|
+
expect(error.message).toContain("wrapped message");
|
|
14
|
+
expect(error.message).toContain("original error");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("Integrates cause message", () => {
|
|
18
|
+
const cause = new Error("cause message");
|
|
19
|
+
const error = new SdError(cause, "main message");
|
|
20
|
+
|
|
21
|
+
expect(error.message).toContain("main message");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("Handles multi-level cause chain", () => {
|
|
25
|
+
const root = new Error("root error");
|
|
26
|
+
const middle = new SdError(root, "middle error");
|
|
27
|
+
const top = new SdError(middle, "top error");
|
|
28
|
+
|
|
29
|
+
expect(top.message).toContain("top error");
|
|
30
|
+
expect(top.message).toContain("middle error");
|
|
31
|
+
expect(top.message).toContain("root error");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("Integrates cause stack to current stack", () => {
|
|
35
|
+
const cause = new Error("cause error");
|
|
36
|
+
const error = new SdError(cause, "main error");
|
|
37
|
+
|
|
38
|
+
expect(error.stack).toContain("---- cause stack ----");
|
|
39
|
+
expect(error.stack).toContain(cause.stack);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("Converts non-Error object passed as cause using String()", () => {
|
|
43
|
+
// number
|
|
44
|
+
const errorFromNumber = new SdError(42, "number cause");
|
|
45
|
+
expect(errorFromNumber.message).toContain("42");
|
|
46
|
+
|
|
47
|
+
// object
|
|
48
|
+
const errorFromObject = new SdError({ code: 500, reason: "server error" }, "object cause");
|
|
49
|
+
expect(errorFromObject.message).toContain("object cause");
|
|
50
|
+
|
|
51
|
+
// null/undefined
|
|
52
|
+
const errorFromNull = new SdError(null, "null cause");
|
|
53
|
+
expect(errorFromNull.message).toContain("null cause");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
|
|
59
|
+
//#region ArgumentError
|
|
60
|
+
|
|
61
|
+
describe("ArgumentError", () => {
|
|
62
|
+
it("Creates with argObj", () => {
|
|
63
|
+
const error = new ArgumentError("invalid argument", { param: "value", expected: "string" });
|
|
64
|
+
|
|
65
|
+
// argObj included in message as YAML format
|
|
66
|
+
expect(error.message).toContain("invalid argument");
|
|
67
|
+
expect(error.message).toContain("param");
|
|
68
|
+
expect(error.message).toContain("value");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("Creates with only argObj without message", () => {
|
|
72
|
+
const error = new ArgumentError({ key: "value" });
|
|
73
|
+
|
|
74
|
+
expect(error.message).toContain("Invalid arguments");
|
|
75
|
+
expect(error.message).toContain("key");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
});
|