@simplysm/core-common 13.0.76 → 13.0.78
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 +64 -21
- package/dist/extensions/arr-ext.d.ts +1 -1
- package/dist/extensions/arr-ext.d.ts.map +1 -1
- package/dist/extensions/arr-ext.helpers.d.ts +8 -0
- package/dist/extensions/arr-ext.helpers.d.ts.map +1 -1
- package/dist/extensions/arr-ext.helpers.js +65 -0
- package/dist/extensions/arr-ext.helpers.js.map +2 -2
- package/dist/extensions/arr-ext.js +16 -124
- package/dist/extensions/arr-ext.js.map +2 -2
- package/dist/extensions/arr-ext.types.d.ts +40 -32
- package/dist/extensions/arr-ext.types.d.ts.map +1 -1
- package/dist/extensions/map-ext.js.map +1 -1
- package/dist/extensions/set-ext.js.map +1 -1
- package/dist/features/event-emitter.d.ts +4 -4
- package/dist/features/event-emitter.d.ts.map +1 -1
- package/dist/features/event-emitter.js.map +1 -1
- package/dist/features/serial-queue.js +2 -2
- package/dist/features/serial-queue.js.map +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -13
- package/dist/index.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/types/uuid.d.ts +2 -2
- package/dist/types/uuid.d.ts.map +1 -1
- package/dist/types/uuid.js +1 -1
- package/dist/types/uuid.js.map +1 -1
- package/dist/utils/bytes.d.ts +10 -10
- package/dist/utils/bytes.d.ts.map +1 -1
- package/dist/utils/bytes.js +10 -10
- package/dist/utils/bytes.js.map +1 -1
- package/dist/utils/date-format.d.ts +1 -1
- package/dist/utils/date-format.d.ts.map +1 -1
- package/dist/utils/date-format.js +2 -2
- package/dist/utils/date-format.js.map +1 -1
- package/dist/utils/error.d.ts +1 -1
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +2 -2
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/json.d.ts +4 -2
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/json.js +9 -9
- package/dist/utils/json.js.map +1 -1
- package/dist/utils/num.d.ts +10 -10
- package/dist/utils/num.d.ts.map +1 -1
- package/dist/utils/num.js +11 -11
- package/dist/utils/num.js.map +1 -1
- package/dist/utils/obj.d.ts +40 -40
- package/dist/utils/obj.d.ts.map +1 -1
- package/dist/utils/obj.js +102 -99
- package/dist/utils/obj.js.map +1 -1
- package/dist/utils/path.d.ts +3 -3
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +6 -6
- package/dist/utils/path.js.map +1 -1
- package/dist/utils/primitive.d.ts +1 -1
- package/dist/utils/primitive.d.ts.map +1 -1
- package/dist/utils/primitive.js +2 -2
- package/dist/utils/primitive.js.map +1 -1
- package/dist/utils/str.d.ts +16 -16
- package/dist/utils/str.d.ts.map +1 -1
- package/dist/utils/str.js +16 -16
- package/dist/utils/str.js.map +1 -1
- package/dist/utils/transferable.d.ts +3 -3
- package/dist/utils/transferable.d.ts.map +1 -1
- package/dist/utils/transferable.js +10 -10
- package/dist/utils/transferable.js.map +1 -1
- package/dist/utils/wait.d.ts +2 -2
- package/dist/utils/wait.d.ts.map +1 -1
- package/dist/utils/wait.js +5 -5
- package/dist/utils/wait.js.map +1 -1
- package/dist/utils/xml.d.ts +2 -2
- package/dist/utils/xml.d.ts.map +1 -1
- package/dist/utils/xml.js +4 -4
- package/dist/utils/xml.js.map +1 -1
- package/dist/{zip/sd-zip.d.ts → utils/zip.d.ts} +1 -1
- package/dist/utils/zip.d.ts.map +1 -0
- package/dist/{zip/sd-zip.js → utils/zip.js} +1 -1
- package/dist/{zip/sd-zip.js.map → utils/zip.js.map} +1 -1
- package/package.json +1 -1
- package/src/extensions/arr-ext.helpers.ts +86 -0
- package/src/extensions/arr-ext.ts +22 -170
- package/src/extensions/arr-ext.types.ts +76 -48
- package/src/extensions/map-ext.ts +3 -3
- package/src/extensions/set-ext.ts +2 -2
- package/src/features/event-emitter.ts +6 -6
- package/src/features/serial-queue.ts +2 -2
- package/src/index.ts +16 -16
- 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/types/uuid.ts +2 -2
- package/src/utils/bytes.ts +15 -15
- package/src/utils/date-format.ts +1 -1
- package/src/utils/error.ts +1 -1
- package/src/utils/json.ts +9 -7
- package/src/utils/num.ts +15 -15
- package/src/utils/obj.ts +119 -116
- package/src/utils/path.ts +3 -3
- package/src/utils/primitive.ts +1 -1
- package/src/utils/str.ts +16 -16
- package/src/utils/transferable.ts +9 -9
- package/src/utils/wait.ts +3 -3
- package/src/utils/xml.ts +2 -2
- package/tests/extensions/array-extension.spec.ts +7 -5
- package/tests/types/uuid.spec.ts +4 -4
- package/tests/utils/bytes-utils.spec.ts +42 -49
- package/tests/utils/date-format.spec.ts +89 -88
- package/tests/utils/debounce-queue.spec.ts +3 -1
- package/tests/utils/json.spec.ts +61 -68
- package/tests/utils/number.spec.ts +41 -46
- package/tests/utils/object.spec.ts +120 -139
- package/tests/utils/path.spec.ts +19 -19
- package/tests/utils/primitive.spec.ts +12 -12
- package/tests/utils/string.spec.ts +66 -74
- package/tests/utils/transferable.spec.ts +55 -62
- package/tests/utils/wait.spec.ts +10 -10
- package/tests/utils/xml.spec.ts +25 -25
- package/dist/zip/sd-zip.d.ts.map +0 -1
- /package/src/{zip/sd-zip.ts → utils/zip.ts} +0 -0
- /package/tests/{zip/sd-zip.spec.ts → utils/zip.spec.ts} +0 -0
package/src/utils/path.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Combine paths (path.join replacement)
|
|
12
12
|
* @note Supports POSIX style paths only (slash `/`)
|
|
13
13
|
*/
|
|
14
|
-
export function
|
|
14
|
+
export function join(...segments: string[]): string {
|
|
15
15
|
return segments
|
|
16
16
|
.map((s, i) => (i === 0 ? s.replace(/\/+$/, "") : s.replace(/^\/+|\/+$/g, "")))
|
|
17
17
|
.filter(Boolean)
|
|
@@ -21,7 +21,7 @@ export function pathJoin(...segments: string[]): string {
|
|
|
21
21
|
/**
|
|
22
22
|
* Extract filename (path.basename replacement)
|
|
23
23
|
*/
|
|
24
|
-
export function
|
|
24
|
+
export function basename(filePath: string, ext?: string): string {
|
|
25
25
|
const name = filePath.split("/").pop() ?? "";
|
|
26
26
|
if (ext != null && ext !== "" && name.endsWith(ext)) {
|
|
27
27
|
return name.slice(0, -ext.length);
|
|
@@ -33,7 +33,7 @@ export function pathBasename(filePath: string, ext?: string): string {
|
|
|
33
33
|
* Extract file extension (path.extname replacement)
|
|
34
34
|
* @note Hidden files (e.g., `.gitignore`) return empty string (same as Node.js path.extname)
|
|
35
35
|
*/
|
|
36
|
-
export function
|
|
36
|
+
export function extname(filePath: string): string {
|
|
37
37
|
const name = filePath.split("/").pop() ?? "";
|
|
38
38
|
const dotIndex = name.lastIndexOf(".");
|
|
39
39
|
return dotIndex > 0 ? name.slice(dotIndex) : "";
|
package/src/utils/primitive.ts
CHANGED
|
@@ -20,7 +20,7 @@ import type { PrimitiveTypeMap, PrimitiveTypeStr } from "../common.types";
|
|
|
20
20
|
* getPrimitiveTypeStr(new DateTime()) // "DateTime"
|
|
21
21
|
* getPrimitiveTypeStr(new Uint8Array()) // "Bytes"
|
|
22
22
|
*/
|
|
23
|
-
export function
|
|
23
|
+
export function typeStr(value: PrimitiveTypeMap[PrimitiveTypeStr]): PrimitiveTypeStr {
|
|
24
24
|
if (typeof value === "string") return "string";
|
|
25
25
|
if (typeof value === "number") return "number";
|
|
26
26
|
if (typeof value === "boolean") return "boolean";
|
package/src/utils/str.ts
CHANGED
|
@@ -28,10 +28,10 @@ const suffixTable = {
|
|
|
28
28
|
* - `"라"`: 이라/라 (ira/ra - copula particle)
|
|
29
29
|
*
|
|
30
30
|
* @example
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* getKoreanSuffix("Apple", "을") // "를"
|
|
32
|
+
* getKoreanSuffix("책", "이") // "이"
|
|
33
33
|
*/
|
|
34
|
-
export function
|
|
34
|
+
export function getKoreanSuffix(
|
|
35
35
|
text: string,
|
|
36
36
|
type: "을" | "은" | "이" | "와" | "랑" | "로" | "라",
|
|
37
37
|
): string {
|
|
@@ -147,10 +147,10 @@ const fullWidthCharRegex = new RegExp(`[${Object.keys(fullWidthCharMap).join("")
|
|
|
147
147
|
* - Full-width parentheses (() → ())
|
|
148
148
|
*
|
|
149
149
|
* @example
|
|
150
|
-
*
|
|
151
|
-
*
|
|
150
|
+
* replaceFullWidth("A123") // "A123"
|
|
151
|
+
* replaceFullWidth("(株)") // "(株)"
|
|
152
152
|
*/
|
|
153
|
-
export function
|
|
153
|
+
export function replaceFullWidth(str: string): string {
|
|
154
154
|
return str.replace(fullWidthCharRegex, (char) => fullWidthCharMap[char] ?? char);
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -164,7 +164,7 @@ export function strReplaceFullWidth(str: string): string {
|
|
|
164
164
|
* @example "hello_world" → "HelloWorld"
|
|
165
165
|
* @example "hello.world" → "HelloWorld"
|
|
166
166
|
*/
|
|
167
|
-
export function
|
|
167
|
+
export function toPascalCase(str: string): string {
|
|
168
168
|
return str
|
|
169
169
|
.replace(/[-._][a-z]/g, (m) => m[1].toUpperCase())
|
|
170
170
|
.replace(/^[a-z]/, (m) => m.toUpperCase());
|
|
@@ -176,7 +176,7 @@ export function strToPascalCase(str: string): string {
|
|
|
176
176
|
* @example "hello_world" → "helloWorld"
|
|
177
177
|
* @example "HelloWorld" → "helloWorld"
|
|
178
178
|
*/
|
|
179
|
-
export function
|
|
179
|
+
export function toCamelCase(str: string): string {
|
|
180
180
|
return str
|
|
181
181
|
.replace(/[-._][a-z]/g, (m) => m[1].toUpperCase())
|
|
182
182
|
.replace(/^[A-Z]/, (m) => m.toLowerCase());
|
|
@@ -192,7 +192,7 @@ export function strToCamelCase(str: string): string {
|
|
|
192
192
|
* @example "Hello-World" → "hello--world" (existing separators are preserved)
|
|
193
193
|
* @example "XMLParser" → "x-m-l-parser" (consecutive uppercase letters are separated)
|
|
194
194
|
*/
|
|
195
|
-
export function
|
|
195
|
+
export function toKebabCase(str: string): string {
|
|
196
196
|
return toCaseWithSeparator(str, "-");
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -206,7 +206,7 @@ export function strToKebabCase(str: string): string {
|
|
|
206
206
|
* @example "Hello_World" → "hello__world" (existing separators are preserved)
|
|
207
207
|
* @example "XMLParser" → "x_m_l_parser" (consecutive uppercase letters are separated)
|
|
208
208
|
*/
|
|
209
|
-
export function
|
|
209
|
+
export function toSnakeCase(str: string): string {
|
|
210
210
|
return toCaseWithSeparator(str, "_");
|
|
211
211
|
}
|
|
212
212
|
|
|
@@ -228,7 +228,7 @@ function toCaseWithSeparator(str: string, separator: string): string {
|
|
|
228
228
|
*
|
|
229
229
|
* @example
|
|
230
230
|
* const name: string | undefined = getValue();
|
|
231
|
-
* if (
|
|
231
|
+
* if (isNullOrEmpty(name)) {
|
|
232
232
|
* // name: "" | undefined
|
|
233
233
|
* console.log("Name is empty");
|
|
234
234
|
* } else {
|
|
@@ -236,7 +236,7 @@ function toCaseWithSeparator(str: string, separator: string): string {
|
|
|
236
236
|
* console.log(`Name: ${name}`);
|
|
237
237
|
* }
|
|
238
238
|
*/
|
|
239
|
-
export function
|
|
239
|
+
export function isNullOrEmpty(str: string | undefined): str is "" | undefined {
|
|
240
240
|
return str == null || str === "";
|
|
241
241
|
}
|
|
242
242
|
|
|
@@ -249,11 +249,11 @@ export function strIsNullOrEmpty(str: string | undefined): str is "" | undefined
|
|
|
249
249
|
* @returns A new string with the insertion applied
|
|
250
250
|
*
|
|
251
251
|
* @example
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
252
|
+
* insert("Hello World", 5, ","); // "Hello, World"
|
|
253
|
+
* insert("abc", 0, "X"); // "Xabc"
|
|
254
|
+
* insert("abc", 3, "X"); // "abcX"
|
|
255
255
|
*/
|
|
256
|
-
export function
|
|
256
|
+
export function insert(str: string, index: number, insertString: string): string {
|
|
257
257
|
return str.substring(0, index) + insertString + str.substring(index);
|
|
258
258
|
}
|
|
259
259
|
|
|
@@ -32,7 +32,7 @@ type Transferable = ArrayBuffer;
|
|
|
32
32
|
* worker.postMessage(result, transferList);
|
|
33
33
|
*
|
|
34
34
|
* // Receive data from Worker
|
|
35
|
-
* const decoded =
|
|
35
|
+
* const decoded = decode(event.data);
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
//#region encode
|
|
@@ -43,7 +43,7 @@ type Transferable = ArrayBuffer;
|
|
|
43
43
|
*
|
|
44
44
|
* @throws TypeError if circular reference is detected
|
|
45
45
|
*/
|
|
46
|
-
export function
|
|
46
|
+
export function encode(obj: unknown): {
|
|
47
47
|
result: unknown;
|
|
48
48
|
transferList: Transferable[];
|
|
49
49
|
} {
|
|
@@ -204,7 +204,7 @@ function encodeImpl(
|
|
|
204
204
|
* Convert serialized objects to objects using Simplysm types
|
|
205
205
|
* Deserialize data received from a Worker
|
|
206
206
|
*/
|
|
207
|
-
export function
|
|
207
|
+
export function decode(obj: unknown): unknown {
|
|
208
208
|
if (obj == null) return obj;
|
|
209
209
|
|
|
210
210
|
// 1. Restore special types from tagged objects
|
|
@@ -239,22 +239,22 @@ export function transferableDecode(obj: unknown): unknown {
|
|
|
239
239
|
err.stack = errorData.stack;
|
|
240
240
|
|
|
241
241
|
if (errorData.code !== undefined) err.code = errorData.code;
|
|
242
|
-
if (errorData.cause !== undefined) (err as Error).cause =
|
|
243
|
-
if (errorData.detail !== undefined) err.detail =
|
|
242
|
+
if (errorData.cause !== undefined) (err as Error).cause = decode(errorData.cause);
|
|
243
|
+
if (errorData.detail !== undefined) err.detail = decode(errorData.detail);
|
|
244
244
|
return err;
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
// 2. Array recursion
|
|
249
249
|
if (Array.isArray(obj)) {
|
|
250
|
-
return obj.map((item) =>
|
|
250
|
+
return obj.map((item) => decode(item));
|
|
251
251
|
}
|
|
252
252
|
|
|
253
253
|
// 3. Map recursion
|
|
254
254
|
if (obj instanceof Map) {
|
|
255
255
|
const newMap = new Map<unknown, unknown>();
|
|
256
256
|
for (const [k, v] of obj) {
|
|
257
|
-
newMap.set(
|
|
257
|
+
newMap.set(decode(k), decode(v));
|
|
258
258
|
}
|
|
259
259
|
return newMap;
|
|
260
260
|
}
|
|
@@ -263,7 +263,7 @@ export function transferableDecode(obj: unknown): unknown {
|
|
|
263
263
|
if (obj instanceof Set) {
|
|
264
264
|
const newSet = new Set<unknown>();
|
|
265
265
|
for (const v of obj) {
|
|
266
|
-
newSet.add(
|
|
266
|
+
newSet.add(decode(v));
|
|
267
267
|
}
|
|
268
268
|
return newSet;
|
|
269
269
|
}
|
|
@@ -273,7 +273,7 @@ export function transferableDecode(obj: unknown): unknown {
|
|
|
273
273
|
const record = obj as Record<string, unknown>;
|
|
274
274
|
const result: Record<string, unknown> = {};
|
|
275
275
|
for (const key of Object.keys(record)) {
|
|
276
|
-
result[key] =
|
|
276
|
+
result[key] = decode(record[key]);
|
|
277
277
|
}
|
|
278
278
|
return result;
|
|
279
279
|
}
|
package/src/utils/wait.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { TimeoutError } from "../errors/timeout-error";
|
|
|
15
15
|
* await waitUntil(() => someCondition, 100, 3);
|
|
16
16
|
* @throws TimeoutError when maximum number of attempts is exceeded
|
|
17
17
|
*/
|
|
18
|
-
export async function
|
|
18
|
+
export async function until(
|
|
19
19
|
forwarder: () => boolean | Promise<boolean>,
|
|
20
20
|
milliseconds?: number,
|
|
21
21
|
maxCount?: number,
|
|
@@ -27,7 +27,7 @@ export async function waitUntil(
|
|
|
27
27
|
throw new TimeoutError(count);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
await
|
|
30
|
+
await time(milliseconds ?? 100);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -35,6 +35,6 @@ export async function waitUntil(
|
|
|
35
35
|
* Wait for a specified amount of time
|
|
36
36
|
* @param millisecond Wait time (ms)
|
|
37
37
|
*/
|
|
38
|
-
export async function
|
|
38
|
+
export async function time(millisecond: number): Promise<void> {
|
|
39
39
|
return new Promise<void>((resolve) => setTimeout(resolve, millisecond));
|
|
40
40
|
}
|
package/src/utils/xml.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
|
19
19
|
* xmlParse('<root id="1"><item>hello</item></root>');
|
|
20
20
|
* // { root: { $: { id: "1" }, item: [{ _: "hello" }] } }
|
|
21
21
|
*/
|
|
22
|
-
export function
|
|
22
|
+
export function parse(str: string, options?: { stripTagPrefix?: boolean }): unknown {
|
|
23
23
|
const result = new XMLParser({
|
|
24
24
|
ignoreAttributes: false,
|
|
25
25
|
attributeNamePrefix: "",
|
|
@@ -53,7 +53,7 @@ export function xmlParse(str: string, options?: { stripTagPrefix?: boolean }): u
|
|
|
53
53
|
* });
|
|
54
54
|
* // '<root id="1"><item>hello</item><item>world</item></root>'
|
|
55
55
|
*/
|
|
56
|
-
export function
|
|
56
|
+
export function stringify(obj: unknown, options?: XmlBuilderOptions): string {
|
|
57
57
|
return new XMLBuilder({
|
|
58
58
|
ignoreAttributes: false,
|
|
59
59
|
attributeNamePrefix: "",
|
|
@@ -196,6 +196,7 @@ describe("Array prototype extensions", () => {
|
|
|
196
196
|
describe("diffs()", () => {
|
|
197
197
|
it("Analyzes differences between arrays", () => {
|
|
198
198
|
interface Item {
|
|
199
|
+
[key: string]: unknown;
|
|
199
200
|
id: number;
|
|
200
201
|
value: string;
|
|
201
202
|
}
|
|
@@ -214,13 +215,13 @@ describe("Array prototype extensions", () => {
|
|
|
214
215
|
|
|
215
216
|
const result = source.diffs(target, { keys: ["id"] });
|
|
216
217
|
|
|
217
|
-
const deleted = result.find((d) => d.source?.id === 1);
|
|
218
|
+
const deleted = result.find((d) => d.source?.["id"] === 1);
|
|
218
219
|
expect(deleted?.target).toBe(undefined);
|
|
219
220
|
|
|
220
|
-
const updated = result.find((d) => d.source?.id === 3);
|
|
221
|
-
expect(updated?.target?.value).toBe("changed");
|
|
221
|
+
const updated = result.find((d) => d.source?.["id"] === 3);
|
|
222
|
+
expect(updated?.target?.["value"]).toBe("changed");
|
|
222
223
|
|
|
223
|
-
const inserted = result.find((d) => d.target?.id === 4);
|
|
224
|
+
const inserted = result.find((d) => d.target?.["id"] === 4);
|
|
224
225
|
expect(inserted?.source).toBe(undefined);
|
|
225
226
|
});
|
|
226
227
|
});
|
|
@@ -280,6 +281,7 @@ describe("Array prototype extensions", () => {
|
|
|
280
281
|
describe("merge()", () => {
|
|
281
282
|
it("Merges modified items", () => {
|
|
282
283
|
interface Item {
|
|
284
|
+
[key: string]: unknown;
|
|
283
285
|
id: number;
|
|
284
286
|
value: string;
|
|
285
287
|
}
|
|
@@ -296,7 +298,7 @@ describe("Array prototype extensions", () => {
|
|
|
296
298
|
const result = source.merge(target, { keys: ["id"] });
|
|
297
299
|
|
|
298
300
|
expect(result).toHaveLength(2);
|
|
299
|
-
expect(result.find((r) => r
|
|
301
|
+
expect(result.find((r) => r["id"] === 2)?.["value"]).toBe("changed");
|
|
300
302
|
});
|
|
301
303
|
});
|
|
302
304
|
|
package/tests/types/uuid.spec.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import { Uuid } from "@simplysm/core-common";
|
|
3
3
|
|
|
4
4
|
describe("Uuid", () => {
|
|
5
|
-
describe("
|
|
5
|
+
describe("generate()", () => {
|
|
6
6
|
it("Generates valid UUID v4 format", () => {
|
|
7
|
-
const uuid = Uuid.
|
|
7
|
+
const uuid = Uuid.generate();
|
|
8
8
|
const str = uuid.toString();
|
|
9
9
|
|
|
10
10
|
// UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
@@ -12,8 +12,8 @@ describe("Uuid", () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it("Generates new UUID each time", () => {
|
|
15
|
-
const uuid1 = Uuid.
|
|
16
|
-
const uuid2 = Uuid.
|
|
15
|
+
const uuid1 = Uuid.generate();
|
|
16
|
+
const uuid2 = Uuid.generate();
|
|
17
17
|
|
|
18
18
|
expect(uuid1.toString()).not.toBe(uuid2.toString());
|
|
19
19
|
});
|
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
ArgumentError,
|
|
4
|
-
bytesConcat as concat,
|
|
5
|
-
bytesToHex as toHex,
|
|
6
|
-
bytesFromHex as fromHex,
|
|
7
|
-
bytesToBase64 as toBase64,
|
|
8
|
-
bytesFromBase64 as fromBase64,
|
|
9
|
-
} from "@simplysm/core-common";
|
|
2
|
+
import { ArgumentError, bytes } from "@simplysm/core-common";
|
|
10
3
|
|
|
11
4
|
describe("BytesUtils", () => {
|
|
12
5
|
//#region concat
|
|
13
6
|
|
|
14
|
-
describe("concat()", () => {
|
|
7
|
+
describe("bytes.concat()", () => {
|
|
15
8
|
it("Concatenates multiple Uint8Arrays", () => {
|
|
16
9
|
const arr1 = new Uint8Array([1, 2, 3]);
|
|
17
10
|
const arr2 = new Uint8Array([4, 5]);
|
|
18
11
|
const arr3 = new Uint8Array([6, 7, 8, 9]);
|
|
19
12
|
|
|
20
|
-
const result = concat([arr1, arr2, arr3]);
|
|
13
|
+
const result = bytes.concat([arr1, arr2, arr3]);
|
|
21
14
|
|
|
22
15
|
expect(result).toEqual(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]));
|
|
23
16
|
});
|
|
24
17
|
|
|
25
18
|
it("Handles empty array", () => {
|
|
26
|
-
const result = concat([]);
|
|
19
|
+
const result = bytes.concat([]);
|
|
27
20
|
|
|
28
21
|
expect(result).toEqual(new Uint8Array([]));
|
|
29
22
|
expect(result.length).toBe(0);
|
|
@@ -34,7 +27,7 @@ describe("BytesUtils", () => {
|
|
|
34
27
|
const arr2 = new Uint8Array([]);
|
|
35
28
|
const arr3 = new Uint8Array([3, 4]);
|
|
36
29
|
|
|
37
|
-
const result = concat([arr1, arr2, arr3]);
|
|
30
|
+
const result = bytes.concat([arr1, arr2, arr3]);
|
|
38
31
|
|
|
39
32
|
expect(result).toEqual(new Uint8Array([1, 2, 3, 4]));
|
|
40
33
|
});
|
|
@@ -44,56 +37,56 @@ describe("BytesUtils", () => {
|
|
|
44
37
|
|
|
45
38
|
//#region toHex/fromHex
|
|
46
39
|
|
|
47
|
-
describe("toHex()", () => {
|
|
40
|
+
describe("bytes.toHex()", () => {
|
|
48
41
|
it("Converts Uint8Array to hex string", () => {
|
|
49
|
-
const
|
|
42
|
+
const data = new Uint8Array([0, 1, 15, 16, 255]);
|
|
50
43
|
|
|
51
|
-
const result = toHex(
|
|
44
|
+
const result = bytes.toHex(data);
|
|
52
45
|
|
|
53
46
|
expect(result).toBe("00010f10ff");
|
|
54
47
|
});
|
|
55
48
|
|
|
56
49
|
it("Handles empty array", () => {
|
|
57
|
-
const result = toHex(new Uint8Array([]));
|
|
50
|
+
const result = bytes.toHex(new Uint8Array([]));
|
|
58
51
|
|
|
59
52
|
expect(result).toBe("");
|
|
60
53
|
});
|
|
61
54
|
|
|
62
55
|
it("Handles single byte", () => {
|
|
63
|
-
expect(toHex(new Uint8Array([0]))).toBe("00");
|
|
64
|
-
expect(toHex(new Uint8Array([255]))).toBe("ff");
|
|
56
|
+
expect(bytes.toHex(new Uint8Array([0]))).toBe("00");
|
|
57
|
+
expect(bytes.toHex(new Uint8Array([255]))).toBe("ff");
|
|
65
58
|
});
|
|
66
59
|
});
|
|
67
60
|
|
|
68
|
-
describe("fromHex()", () => {
|
|
61
|
+
describe("bytes.fromHex()", () => {
|
|
69
62
|
it("Converts hex string to Uint8Array", () => {
|
|
70
|
-
const result = fromHex("00010f10ff");
|
|
63
|
+
const result = bytes.fromHex("00010f10ff");
|
|
71
64
|
|
|
72
65
|
expect(result).toEqual(new Uint8Array([0, 1, 15, 16, 255]));
|
|
73
66
|
});
|
|
74
67
|
|
|
75
68
|
it("Handles empty string", () => {
|
|
76
|
-
const result = fromHex("");
|
|
69
|
+
const result = bytes.fromHex("");
|
|
77
70
|
|
|
78
71
|
expect(result).toEqual(new Uint8Array([]));
|
|
79
72
|
});
|
|
80
73
|
|
|
81
74
|
it("Handles uppercase hex", () => {
|
|
82
|
-
const result = fromHex("FF0A");
|
|
75
|
+
const result = bytes.fromHex("FF0A");
|
|
83
76
|
|
|
84
77
|
expect(result).toEqual(new Uint8Array([255, 10]));
|
|
85
78
|
});
|
|
86
79
|
|
|
87
80
|
it("Throws error for odd-length string", () => {
|
|
88
|
-
expect(() => fromHex("abc")).toThrow(ArgumentError);
|
|
89
|
-
expect(() => fromHex("a")).toThrow(ArgumentError);
|
|
90
|
-
expect(() => fromHex("12345")).toThrow(ArgumentError);
|
|
81
|
+
expect(() => bytes.fromHex("abc")).toThrow(ArgumentError);
|
|
82
|
+
expect(() => bytes.fromHex("a")).toThrow(ArgumentError);
|
|
83
|
+
expect(() => bytes.fromHex("12345")).toThrow(ArgumentError);
|
|
91
84
|
});
|
|
92
85
|
|
|
93
86
|
it("Throws error for invalid hex characters", () => {
|
|
94
|
-
expect(() => fromHex("zz")).toThrow(ArgumentError);
|
|
95
|
-
expect(() => fromHex("gh")).toThrow(ArgumentError);
|
|
96
|
-
expect(() => fromHex("12g4")).toThrow(ArgumentError);
|
|
87
|
+
expect(() => bytes.fromHex("zz")).toThrow(ArgumentError);
|
|
88
|
+
expect(() => bytes.fromHex("gh")).toThrow(ArgumentError);
|
|
89
|
+
expect(() => bytes.fromHex("12g4")).toThrow(ArgumentError);
|
|
97
90
|
});
|
|
98
91
|
});
|
|
99
92
|
|
|
@@ -104,8 +97,8 @@ describe("BytesUtils", () => {
|
|
|
104
97
|
original[i] = i;
|
|
105
98
|
}
|
|
106
99
|
|
|
107
|
-
const hex = toHex(original);
|
|
108
|
-
const restored = fromHex(hex);
|
|
100
|
+
const hex = bytes.toHex(original);
|
|
101
|
+
const restored = bytes.fromHex(hex);
|
|
109
102
|
|
|
110
103
|
expect(restored).toEqual(original);
|
|
111
104
|
});
|
|
@@ -115,60 +108,60 @@ describe("BytesUtils", () => {
|
|
|
115
108
|
|
|
116
109
|
//#region toBase64/fromBase64
|
|
117
110
|
|
|
118
|
-
describe("toBase64()", () => {
|
|
111
|
+
describe("bytes.toBase64()", () => {
|
|
119
112
|
it("Handles empty array", () => {
|
|
120
|
-
expect(toBase64(new Uint8Array([]))).toBe("");
|
|
113
|
+
expect(bytes.toBase64(new Uint8Array([]))).toBe("");
|
|
121
114
|
});
|
|
122
115
|
|
|
123
116
|
it("Converts general data", () => {
|
|
124
|
-
expect(toBase64(new Uint8Array([72, 101, 108, 108, 111]))).toBe("SGVsbG8=");
|
|
117
|
+
expect(bytes.toBase64(new Uint8Array([72, 101, 108, 108, 111]))).toBe("SGVsbG8=");
|
|
125
118
|
});
|
|
126
119
|
|
|
127
120
|
it("Handles large data (1MB) without stack overflow", () => {
|
|
128
121
|
const data = new Uint8Array(1024 * 1024);
|
|
129
|
-
expect(() => toBase64(data)).not.toThrow();
|
|
122
|
+
expect(() => bytes.toBase64(data)).not.toThrow();
|
|
130
123
|
});
|
|
131
124
|
|
|
132
125
|
it("Handles case with no padding needed", () => {
|
|
133
126
|
// Multiple of 3 length - no padding
|
|
134
|
-
expect(toBase64(new Uint8Array([1, 2, 3]))).toBe("AQID");
|
|
127
|
+
expect(bytes.toBase64(new Uint8Array([1, 2, 3]))).toBe("AQID");
|
|
135
128
|
});
|
|
136
129
|
|
|
137
130
|
it("Handles case with single padding needed", () => {
|
|
138
131
|
// Remainder 2 when divided by 3 - 1 padding
|
|
139
|
-
expect(toBase64(new Uint8Array([1, 2]))).toBe("AQI=");
|
|
132
|
+
expect(bytes.toBase64(new Uint8Array([1, 2]))).toBe("AQI=");
|
|
140
133
|
});
|
|
141
134
|
|
|
142
135
|
it("Handles case with double padding needed", () => {
|
|
143
136
|
// Remainder 1 when divided by 3 - 2 padding
|
|
144
|
-
expect(toBase64(new Uint8Array([1]))).toBe("AQ==");
|
|
137
|
+
expect(bytes.toBase64(new Uint8Array([1]))).toBe("AQ==");
|
|
145
138
|
});
|
|
146
139
|
});
|
|
147
140
|
|
|
148
|
-
describe("fromBase64()", () => {
|
|
141
|
+
describe("bytes.fromBase64()", () => {
|
|
149
142
|
it("Handles empty string", () => {
|
|
150
|
-
expect(fromBase64("")).toEqual(new Uint8Array([]));
|
|
143
|
+
expect(bytes.fromBase64("")).toEqual(new Uint8Array([]));
|
|
151
144
|
});
|
|
152
145
|
|
|
153
146
|
it("Converts general data", () => {
|
|
154
|
-
expect(fromBase64("SGVsbG8=")).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
|
|
147
|
+
expect(bytes.fromBase64("SGVsbG8=")).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
|
|
155
148
|
});
|
|
156
149
|
|
|
157
150
|
it("Throws error for invalid base64 characters", () => {
|
|
158
|
-
expect(() => fromBase64("!!invalid!!")).toThrow(ArgumentError);
|
|
151
|
+
expect(() => bytes.fromBase64("!!invalid!!")).toThrow(ArgumentError);
|
|
159
152
|
});
|
|
160
153
|
|
|
161
154
|
it("Throws error for invalid base64 length (remainder 1)", () => {
|
|
162
|
-
expect(() => fromBase64("A")).toThrow(ArgumentError);
|
|
163
|
-
expect(() => fromBase64("AAAAA")).toThrow(ArgumentError);
|
|
155
|
+
expect(() => bytes.fromBase64("A")).toThrow(ArgumentError);
|
|
156
|
+
expect(() => bytes.fromBase64("AAAAA")).toThrow(ArgumentError);
|
|
164
157
|
});
|
|
165
158
|
|
|
166
159
|
it("Handles base64 without padding", () => {
|
|
167
|
-
expect(fromBase64("AQID")).toEqual(new Uint8Array([1, 2, 3]));
|
|
160
|
+
expect(bytes.fromBase64("AQID")).toEqual(new Uint8Array([1, 2, 3]));
|
|
168
161
|
});
|
|
169
162
|
|
|
170
163
|
it("Handles base64 with whitespace", () => {
|
|
171
|
-
expect(fromBase64("SGVs bG8=")).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
|
|
164
|
+
expect(bytes.fromBase64("SGVs bG8=")).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
|
|
172
165
|
});
|
|
173
166
|
});
|
|
174
167
|
|
|
@@ -179,8 +172,8 @@ describe("BytesUtils", () => {
|
|
|
179
172
|
original[i] = i;
|
|
180
173
|
}
|
|
181
174
|
|
|
182
|
-
const base64 = toBase64(original);
|
|
183
|
-
const restored = fromBase64(base64);
|
|
175
|
+
const base64 = bytes.toBase64(original);
|
|
176
|
+
const restored = bytes.fromBase64(base64);
|
|
184
177
|
|
|
185
178
|
expect(restored).toEqual(original);
|
|
186
179
|
});
|
|
@@ -192,8 +185,8 @@ describe("BytesUtils", () => {
|
|
|
192
185
|
original[i] = (i * 37 + 13) % 256;
|
|
193
186
|
}
|
|
194
187
|
|
|
195
|
-
const base64 = toBase64(original);
|
|
196
|
-
const restored = fromBase64(base64);
|
|
188
|
+
const base64 = bytes.toBase64(original);
|
|
189
|
+
const restored = bytes.fromBase64(base64);
|
|
197
190
|
|
|
198
191
|
expect(restored).toEqual(original);
|
|
199
192
|
}
|