@simplysm/core-common 13.0.75 → 13.0.76
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/package.json +3 -3
- package/tests/extensions/array-extension.spec.ts +0 -144
- package/tests/extensions/map-extension.spec.ts +0 -30
- package/tests/extensions/set-extension.spec.ts +0 -7
- package/tests/types/date-only.spec.ts +0 -105
- package/tests/types/date-time.spec.ts +0 -145
- package/tests/types/lazy-gc-map.spec.ts +0 -86
- package/tests/types/time.spec.ts +0 -131
- package/tests/utils/bytes-utils.spec.ts +0 -26
- package/tests/utils/date-format.spec.ts +0 -24
- package/tests/utils/debounce-queue.spec.ts +0 -48
- package/tests/utils/json.spec.ts +0 -79
- package/tests/utils/number.spec.ts +0 -16
- package/tests/utils/path.spec.ts +0 -8
- package/tests/utils/sd-event-emitter.spec.ts +0 -27
- package/tests/utils/serial-queue.spec.ts +0 -60
- package/tests/utils/string.spec.ts +0 -8
- package/tests/utils/template-strings.spec.ts +0 -9
- package/tests/utils/transferable.spec.ts +0 -57
- package/tests/utils/wait.spec.ts +0 -22
- package/tests/zip/sd-zip.spec.ts +0 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/core-common",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.76",
|
|
4
4
|
"description": "Simplysm package - Core module (common)",
|
|
5
5
|
"author": "simplysm",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"./dist/index.js"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@zip.js/zip.js": "^2.8.
|
|
31
|
+
"@zip.js/zip.js": "^2.8.22",
|
|
32
32
|
"consola": "^3.4.2",
|
|
33
|
-
"fast-xml-parser": "^5.4.
|
|
33
|
+
"fast-xml-parser": "^5.4.2",
|
|
34
34
|
"yaml": "^2.8.2"
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -2,65 +2,6 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import "@simplysm/core-common"; // Enable $ extension
|
|
3
3
|
|
|
4
4
|
describe("Array prototype extensions", () => {
|
|
5
|
-
//#region Basic chaining
|
|
6
|
-
|
|
7
|
-
describe("Basic chaining", () => {
|
|
8
|
-
it("Can chain existing array methods", () => {
|
|
9
|
-
const result = [1, 2, 3, 4, 5].filter((x) => x > 2).map((x) => x * 10);
|
|
10
|
-
|
|
11
|
-
expect(result).toEqual([30, 40, 50]);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it("Can chain extension methods", () => {
|
|
15
|
-
const result = [
|
|
16
|
-
{ id: 1, name: "a" },
|
|
17
|
-
{ id: 2, name: "b" },
|
|
18
|
-
].toMap((x) => x.id);
|
|
19
|
-
|
|
20
|
-
expect(result.get(1)).toEqual({ id: 1, name: "a" });
|
|
21
|
-
expect(result.get(2)).toEqual({ id: 2, name: "b" });
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("Can mix array and extension methods chaining", () => {
|
|
25
|
-
const users = [
|
|
26
|
-
{ id: 1, name: "Kim", active: true },
|
|
27
|
-
{ id: 2, name: "Lee", active: false },
|
|
28
|
-
{ id: 3, name: "Park", active: true },
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
const result = users.filter((u) => u.active).toMap((u) => u.id);
|
|
32
|
-
|
|
33
|
-
expect(result.size).toBe(2);
|
|
34
|
-
expect(result.has(1)).toBe(true);
|
|
35
|
-
expect(result.has(3)).toBe(true);
|
|
36
|
-
expect(result.has(2)).toBe(false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("Can chain multiple steps", () => {
|
|
40
|
-
const result = [1, 2, 3, 4, 5]
|
|
41
|
-
.filter((x) => x > 1)
|
|
42
|
-
.map((x) => x * 2)
|
|
43
|
-
.filter((x) => x < 10)
|
|
44
|
-
.toMap((x) => x);
|
|
45
|
-
|
|
46
|
-
expect(result.size).toBe(3);
|
|
47
|
-
expect(result.has(4)).toBe(true);
|
|
48
|
-
expect(result.has(6)).toBe(true);
|
|
49
|
-
expect(result.has(8)).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("Can access array properties", () => {
|
|
53
|
-
const arr = [1, 2, 3];
|
|
54
|
-
|
|
55
|
-
expect(arr.length).toBe(3);
|
|
56
|
-
expect(arr[0]).toBe(1);
|
|
57
|
-
expect(arr[1]).toBe(2);
|
|
58
|
-
expect(arr[2]).toBe(3);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
//#endregion
|
|
63
|
-
|
|
64
5
|
//#region single
|
|
65
6
|
|
|
66
7
|
describe("single()", () => {
|
|
@@ -85,12 +26,6 @@ describe("Array prototype extensions", () => {
|
|
|
85
26
|
expect(([] as number[]).single()).toBe(undefined);
|
|
86
27
|
expect(() => [1, 2].single()).toThrow();
|
|
87
28
|
});
|
|
88
|
-
|
|
89
|
-
it("Can use single after chaining", () => {
|
|
90
|
-
const result = [1, 2, 3, 4, 5].filter((x) => x > 3).single((x) => x === 4);
|
|
91
|
-
|
|
92
|
-
expect(result).toBe(4);
|
|
93
|
-
});
|
|
94
29
|
});
|
|
95
30
|
|
|
96
31
|
//#endregion
|
|
@@ -111,14 +46,6 @@ describe("Array prototype extensions", () => {
|
|
|
111
46
|
|
|
112
47
|
expect(result).toEqual([2, 4, 6]);
|
|
113
48
|
});
|
|
114
|
-
|
|
115
|
-
it("Can use mapAsync after chaining", async () => {
|
|
116
|
-
const result = await [1, 2, 3, 4, 5]
|
|
117
|
-
.filter((x) => x > 2)
|
|
118
|
-
.mapAsync(async (x) => Promise.resolve(x * 10));
|
|
119
|
-
|
|
120
|
-
expect(result).toEqual([30, 40, 50]);
|
|
121
|
-
});
|
|
122
49
|
});
|
|
123
50
|
|
|
124
51
|
describe("filterAsync()", () => {
|
|
@@ -375,61 +302,6 @@ describe("Array prototype extensions", () => {
|
|
|
375
302
|
|
|
376
303
|
//#endregion
|
|
377
304
|
|
|
378
|
-
//#region ReadonlyArray support
|
|
379
|
-
|
|
380
|
-
describe("ReadonlyArray support", () => {
|
|
381
|
-
it("$ can be used with readonly array", () => {
|
|
382
|
-
const arr: readonly number[] = [1, 2, 3];
|
|
383
|
-
const result = arr.filter((x) => x > 1).toMap((x) => x);
|
|
384
|
-
|
|
385
|
-
expect(result.size).toBe(2);
|
|
386
|
-
expect(result.has(2)).toBe(true);
|
|
387
|
-
expect(result.has(3)).toBe(true);
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
//#endregion
|
|
392
|
-
|
|
393
|
-
//#region Various array method chaining
|
|
394
|
-
|
|
395
|
-
describe("Various array method chaining", () => {
|
|
396
|
-
it("flatMap can be chained", () => {
|
|
397
|
-
const result = [
|
|
398
|
-
[1, 2],
|
|
399
|
-
[3, 4],
|
|
400
|
-
]
|
|
401
|
-
.flatMap((x) => x)
|
|
402
|
-
.toMap((x) => x);
|
|
403
|
-
|
|
404
|
-
expect(result.size).toBe(4);
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
it("slice can be chained", () => {
|
|
408
|
-
const result = [1, 2, 3, 4, 5].slice(1, 4).toMap((x) => x);
|
|
409
|
-
|
|
410
|
-
expect(result.size).toBe(3);
|
|
411
|
-
expect(result.has(2)).toBe(true);
|
|
412
|
-
expect(result.has(3)).toBe(true);
|
|
413
|
-
expect(result.has(4)).toBe(true);
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it("concat can be chained", () => {
|
|
417
|
-
const result = [1, 2].concat([3, 4]).toMap((x) => x);
|
|
418
|
-
|
|
419
|
-
expect(result.size).toBe(4);
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it("sort can be chained", () => {
|
|
423
|
-
const result = [3, 1, 2].sort((a, b) => a - b).toMap((x, i) => i);
|
|
424
|
-
|
|
425
|
-
expect(result.get(0)).toBe(1);
|
|
426
|
-
expect(result.get(1)).toBe(2);
|
|
427
|
-
expect(result.get(2)).toBe(3);
|
|
428
|
-
});
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
//#endregion
|
|
432
|
-
|
|
433
305
|
//#region first, last
|
|
434
306
|
|
|
435
307
|
describe("first()", () => {
|
|
@@ -470,12 +342,6 @@ describe("Array prototype extensions", () => {
|
|
|
470
342
|
const result = arr.filterExists();
|
|
471
343
|
expect(result).toEqual([1, 2, 3]);
|
|
472
344
|
});
|
|
473
|
-
|
|
474
|
-
it("Can be chained", () => {
|
|
475
|
-
const arr = [1, null, 2, undefined, 3];
|
|
476
|
-
const result = arr.filterExists().map((x) => x * 2);
|
|
477
|
-
expect(result).toEqual([2, 4, 6]);
|
|
478
|
-
});
|
|
479
345
|
});
|
|
480
346
|
|
|
481
347
|
describe("ofType()", () => {
|
|
@@ -582,11 +448,6 @@ describe("Array prototype extensions", () => {
|
|
|
582
448
|
expect(result).toHaveLength(2);
|
|
583
449
|
});
|
|
584
450
|
|
|
585
|
-
it("Can be chained", () => {
|
|
586
|
-
const result = [1, 2, 2, 3].distinct().map((x) => x * 2);
|
|
587
|
-
expect(result).toEqual([2, 4, 6]);
|
|
588
|
-
});
|
|
589
|
-
|
|
590
451
|
it("Can use custom key with keyFn", () => {
|
|
591
452
|
const arr = [
|
|
592
453
|
{ id: 1, name: "a" },
|
|
@@ -626,11 +487,6 @@ describe("Array prototype extensions", () => {
|
|
|
626
487
|
const result = items.orderBy((x) => x.age);
|
|
627
488
|
expect(result.map((x) => x.age)).toEqual([20, 25, 30]);
|
|
628
489
|
});
|
|
629
|
-
|
|
630
|
-
it("Can be chained", () => {
|
|
631
|
-
const result = [3, 1, 2].orderBy().map((x) => x * 2);
|
|
632
|
-
expect(result).toEqual([2, 4, 6]);
|
|
633
|
-
});
|
|
634
490
|
});
|
|
635
491
|
|
|
636
492
|
describe("orderByDesc()", () => {
|
|
@@ -44,16 +44,6 @@ describe("Map prototype extensions", () => {
|
|
|
44
44
|
expect(map.get("key")).toBe(50);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it("Returns existing value if key exists (direct value)", () => {
|
|
48
|
-
const map = new Map<string, number>();
|
|
49
|
-
map.set("key", 50);
|
|
50
|
-
|
|
51
|
-
const result = map.getOrCreate("key", 100);
|
|
52
|
-
|
|
53
|
-
expect(result).toBe(50);
|
|
54
|
-
expect(map.size).toBe(1);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
47
|
it("Can set empty array as default value", () => {
|
|
58
48
|
const map = new Map<string, number[]>();
|
|
59
49
|
|
|
@@ -121,26 +111,6 @@ describe("Map prototype extensions", () => {
|
|
|
121
111
|
|
|
122
112
|
expect(map.get("key")).toBe("hello world");
|
|
123
113
|
});
|
|
124
|
-
|
|
125
|
-
it("Can update object value", () => {
|
|
126
|
-
const map = new Map<string, { count: number }>();
|
|
127
|
-
map.set("key", { count: 5 });
|
|
128
|
-
|
|
129
|
-
map.update("key", (v) => ({ count: (v?.count ?? 0) + 1 }));
|
|
130
|
-
|
|
131
|
-
expect(map.get("key")).toEqual({ count: 6 });
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("Can update multiple times sequentially", () => {
|
|
135
|
-
const map = new Map<string, number>();
|
|
136
|
-
map.set("counter", 0);
|
|
137
|
-
|
|
138
|
-
map.update("counter", (v) => (v ?? 0) + 1);
|
|
139
|
-
map.update("counter", (v) => (v ?? 0) + 1);
|
|
140
|
-
map.update("counter", (v) => (v ?? 0) + 1);
|
|
141
|
-
|
|
142
|
-
expect(map.get("counter")).toBe(3);
|
|
143
|
-
});
|
|
144
114
|
});
|
|
145
115
|
|
|
146
116
|
//#endregion
|
|
@@ -22,13 +22,6 @@ describe("Set prototype extensions", () => {
|
|
|
22
22
|
|
|
23
23
|
expect(set.size).toBe(4); // 1, 2, 3, 4
|
|
24
24
|
});
|
|
25
|
-
|
|
26
|
-
it("Adds multiple items to empty Set", () => {
|
|
27
|
-
const set = new Set<number>();
|
|
28
|
-
set.adds(1, 2, 3);
|
|
29
|
-
|
|
30
|
-
expect(set.size).toBe(3);
|
|
31
|
-
});
|
|
32
25
|
});
|
|
33
26
|
|
|
34
27
|
//#endregion
|
|
@@ -109,22 +109,6 @@ describe("DateOnly", () => {
|
|
|
109
109
|
expect(() => DateOnly.parse("invalid-date")).toThrow("Failed to parse date format");
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
it("Parses year-end boundary (December 31)", () => {
|
|
113
|
-
const dateOnly = DateOnly.parse("2024-12-31");
|
|
114
|
-
|
|
115
|
-
expect(dateOnly.year).toBe(2024);
|
|
116
|
-
expect(dateOnly.month).toBe(12);
|
|
117
|
-
expect(dateOnly.day).toBe(31);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it("Parses year-start boundary (January 1)", () => {
|
|
121
|
-
const dateOnly = DateOnly.parse("2025-01-01");
|
|
122
|
-
|
|
123
|
-
expect(dateOnly.year).toBe(2025);
|
|
124
|
-
expect(dateOnly.month).toBe(1);
|
|
125
|
-
expect(dateOnly.day).toBe(1);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
112
|
it("Parses February 29 in leap year", () => {
|
|
129
113
|
const dateOnly = DateOnly.parse("2024-02-29");
|
|
130
114
|
|
|
@@ -132,14 +116,6 @@ describe("DateOnly", () => {
|
|
|
132
116
|
expect(dateOnly.month).toBe(2);
|
|
133
117
|
expect(dateOnly.day).toBe(29);
|
|
134
118
|
});
|
|
135
|
-
|
|
136
|
-
it("Parses February 28 in leap year", () => {
|
|
137
|
-
const dateOnly = DateOnly.parse("2024-02-28");
|
|
138
|
-
|
|
139
|
-
expect(dateOnly.year).toBe(2024);
|
|
140
|
-
expect(dateOnly.month).toBe(2);
|
|
141
|
-
expect(dateOnly.day).toBe(28);
|
|
142
|
-
});
|
|
143
119
|
});
|
|
144
120
|
|
|
145
121
|
//#endregion
|
|
@@ -147,37 +123,6 @@ describe("DateOnly", () => {
|
|
|
147
123
|
//#region Getters
|
|
148
124
|
|
|
149
125
|
describe("Getters", () => {
|
|
150
|
-
it("Returns year", () => {
|
|
151
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
152
|
-
expect(dateOnly.year).toBe(2025);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it("Returns month (1-12)", () => {
|
|
156
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
157
|
-
expect(dateOnly.month).toBe(1);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it("Returns day", () => {
|
|
161
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
162
|
-
expect(dateOnly.day).toBe(6);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("Returns tick", () => {
|
|
166
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
167
|
-
expect(dateOnly.tick).toBe(new Date(2025, 0, 6).getTime());
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it("Returns dayOfWeek (Sunday-Saturday: 0-6)", () => {
|
|
171
|
-
// 2025-01-06 is Monday (1)
|
|
172
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
173
|
-
expect(dateOnly.dayOfWeek).toBe(1);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it("Returns isValid", () => {
|
|
177
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
178
|
-
expect(dateOnly.isValid).toBe(true);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
126
|
it("Invalid date returns isValid as false", () => {
|
|
182
127
|
const dateOnly = new DateOnly(NaN);
|
|
183
128
|
expect(dateOnly.isValid).toBe(false);
|
|
@@ -257,18 +202,6 @@ describe("DateOnly", () => {
|
|
|
257
202
|
});
|
|
258
203
|
});
|
|
259
204
|
|
|
260
|
-
describe("setDay()", () => {
|
|
261
|
-
it("Returns new instance with day changed", () => {
|
|
262
|
-
const dateOnly = new DateOnly(2025, 1, 6);
|
|
263
|
-
const newDateOnly = dateOnly.setDay(15);
|
|
264
|
-
|
|
265
|
-
expect(newDateOnly.year).toBe(2025);
|
|
266
|
-
expect(newDateOnly.month).toBe(1);
|
|
267
|
-
expect(newDateOnly.day).toBe(15);
|
|
268
|
-
expect(dateOnly.day).toBe(6); // original immutable
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
|
|
272
205
|
//#endregion
|
|
273
206
|
|
|
274
207
|
//#region addX methods (immutable)
|
|
@@ -379,44 +312,6 @@ describe("DateOnly", () => {
|
|
|
379
312
|
|
|
380
313
|
//#endregion
|
|
381
314
|
|
|
382
|
-
//#region tick comparison
|
|
383
|
-
|
|
384
|
-
describe("tick comparison", () => {
|
|
385
|
-
it("Same dates have same tick", () => {
|
|
386
|
-
const d1 = new DateOnly(2025, 3, 15);
|
|
387
|
-
const d2 = new DateOnly(2025, 3, 15);
|
|
388
|
-
|
|
389
|
-
expect(d1.tick).toBe(d2.tick);
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
it("Different dates have different ticks", () => {
|
|
393
|
-
const d1 = new DateOnly(2025, 3, 15);
|
|
394
|
-
const d2 = new DateOnly(2025, 3, 16);
|
|
395
|
-
|
|
396
|
-
expect(d1.tick).not.toBe(d2.tick);
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
it("Can compare date order by tick", () => {
|
|
400
|
-
const d1 = new DateOnly(2025, 1, 1);
|
|
401
|
-
const d2 = new DateOnly(2025, 6, 15);
|
|
402
|
-
const d3 = new DateOnly(2025, 12, 31);
|
|
403
|
-
|
|
404
|
-
expect(d1.tick).toBeLessThan(d2.tick);
|
|
405
|
-
expect(d2.tick).toBeLessThan(d3.tick);
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
it("Can compare dates with different years by tick", () => {
|
|
409
|
-
const d2024 = new DateOnly(2024, 12, 31);
|
|
410
|
-
const d2025 = new DateOnly(2025, 1, 1);
|
|
411
|
-
|
|
412
|
-
expect(d2024.tick).toBeLessThan(d2025.tick);
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
//#endregion
|
|
417
|
-
|
|
418
|
-
//#endregion
|
|
419
|
-
|
|
420
315
|
//#region Week calculation
|
|
421
316
|
|
|
422
317
|
describe("getWeekSeqOfYear()", () => {
|
|
@@ -48,22 +48,6 @@ describe("DateTime", () => {
|
|
|
48
48
|
expect(dt.day).toBe(29);
|
|
49
49
|
expect(dt.isValid).toBe(true);
|
|
50
50
|
});
|
|
51
|
-
|
|
52
|
-
it("non-leap year February 29th auto-adjusts to March 1st (JS Date behavior)", () => {
|
|
53
|
-
const dt = new DateTime(2023, 2, 29);
|
|
54
|
-
|
|
55
|
-
expect(dt.year).toBe(2023);
|
|
56
|
-
expect(dt.month).toBe(3);
|
|
57
|
-
expect(dt.day).toBe(1);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("invalid month (13) auto-adjusts to next year January 1st (JS Date behavior)", () => {
|
|
61
|
-
const dt = new DateTime(2024, 13, 1);
|
|
62
|
-
|
|
63
|
-
expect(dt.year).toBe(2025);
|
|
64
|
-
expect(dt.month).toBe(1);
|
|
65
|
-
expect(dt.day).toBe(1);
|
|
66
|
-
});
|
|
67
51
|
});
|
|
68
52
|
|
|
69
53
|
describe("parse()", () => {
|
|
@@ -219,42 +203,9 @@ describe("DateTime", () => {
|
|
|
219
203
|
expect(result.month).toBe(11);
|
|
220
204
|
expect(result.day).toBe(15);
|
|
221
205
|
});
|
|
222
|
-
|
|
223
|
-
it("setMonth(25) returns January 2 years later", () => {
|
|
224
|
-
const dt = new DateTime(2024, 6, 15);
|
|
225
|
-
const result = dt.setMonth(25);
|
|
226
|
-
|
|
227
|
-
expect(result.year).toBe(2026);
|
|
228
|
-
expect(result.month).toBe(1);
|
|
229
|
-
expect(result.day).toBe(15);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("setMonth(-13) returns November 2 years earlier", () => {
|
|
233
|
-
const dt = new DateTime(2024, 6, 15);
|
|
234
|
-
const result = dt.setMonth(-13);
|
|
235
|
-
|
|
236
|
-
expect(result.year).toBe(2022);
|
|
237
|
-
expect(result.month).toBe(11);
|
|
238
|
-
expect(result.day).toBe(15);
|
|
239
|
-
});
|
|
240
206
|
});
|
|
241
207
|
|
|
242
208
|
describe("Arithmetic Methods", () => {
|
|
243
|
-
it("addYears", () => {
|
|
244
|
-
const dt1 = new DateTime(2024, 3, 15);
|
|
245
|
-
const dt2 = dt1.addYears(2);
|
|
246
|
-
|
|
247
|
-
expect(dt2.year).toBe(2026);
|
|
248
|
-
expect(dt1.year).toBe(2024); // original unchanged
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it("addMonths", () => {
|
|
252
|
-
const dt1 = new DateTime(2024, 3, 15);
|
|
253
|
-
const dt2 = dt1.addMonths(3);
|
|
254
|
-
|
|
255
|
-
expect(dt2.month).toBe(6);
|
|
256
|
-
});
|
|
257
|
-
|
|
258
209
|
it("addDays", () => {
|
|
259
210
|
const dt1 = new DateTime(2024, 3, 15);
|
|
260
211
|
const dt2 = dt1.addDays(20);
|
|
@@ -263,13 +214,6 @@ describe("DateTime", () => {
|
|
|
263
214
|
expect(dt2.day).toBe(4);
|
|
264
215
|
});
|
|
265
216
|
|
|
266
|
-
it("addHours", () => {
|
|
267
|
-
const dt1 = new DateTime(2024, 3, 15, 10);
|
|
268
|
-
const dt2 = dt1.addHours(5);
|
|
269
|
-
|
|
270
|
-
expect(dt2.hour).toBe(15);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
217
|
it("addMinutes", () => {
|
|
274
218
|
const dt1 = new DateTime(2024, 3, 15, 10, 30);
|
|
275
219
|
const dt2 = dt1.addMinutes(45);
|
|
@@ -277,76 +221,6 @@ describe("DateTime", () => {
|
|
|
277
221
|
expect(dt2.hour).toBe(11);
|
|
278
222
|
expect(dt2.minute).toBe(15);
|
|
279
223
|
});
|
|
280
|
-
|
|
281
|
-
it("addSeconds", () => {
|
|
282
|
-
const dt1 = new DateTime(2024, 3, 15, 10, 30, 45);
|
|
283
|
-
const dt2 = dt1.addSeconds(30);
|
|
284
|
-
|
|
285
|
-
expect(dt2.minute).toBe(31);
|
|
286
|
-
expect(dt2.second).toBe(15);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
it("addMilliseconds", () => {
|
|
290
|
-
const dt1 = new DateTime(2024, 3, 15, 10, 30, 45, 500);
|
|
291
|
-
const dt2 = dt1.addMilliseconds(600);
|
|
292
|
-
|
|
293
|
-
expect(dt2.second).toBe(46);
|
|
294
|
-
expect(dt2.millisecond).toBe(100);
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
//#region tick comparison
|
|
299
|
-
|
|
300
|
-
describe("tick comparison", () => {
|
|
301
|
-
it("same datetime has same tick", () => {
|
|
302
|
-
const dt1 = new DateTime(2025, 3, 15, 10, 30, 45, 123);
|
|
303
|
-
const dt2 = new DateTime(2025, 3, 15, 10, 30, 45, 123);
|
|
304
|
-
|
|
305
|
-
expect(dt1.tick).toBe(dt2.tick);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("different datetime has different tick", () => {
|
|
309
|
-
const dt1 = new DateTime(2025, 3, 15, 10, 30, 45, 123);
|
|
310
|
-
const dt2 = new DateTime(2025, 3, 15, 10, 30, 45, 124);
|
|
311
|
-
|
|
312
|
-
expect(dt1.tick).not.toBe(dt2.tick);
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
it("can compare datetime order using tick", () => {
|
|
316
|
-
const dt1 = new DateTime(2025, 1, 1, 0, 0, 0);
|
|
317
|
-
const dt2 = new DateTime(2025, 6, 15, 12, 30, 0);
|
|
318
|
-
const dt3 = new DateTime(2025, 12, 31, 23, 59, 59);
|
|
319
|
-
|
|
320
|
-
expect(dt1.tick).toBeLessThan(dt2.tick);
|
|
321
|
-
expect(dt2.tick).toBeLessThan(dt3.tick);
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
it("can compare millisecond precision", () => {
|
|
325
|
-
const dt1 = new DateTime(2025, 3, 15, 10, 30, 45, 0);
|
|
326
|
-
const dt2 = new DateTime(2025, 3, 15, 10, 30, 45, 1);
|
|
327
|
-
|
|
328
|
-
expect(dt2.tick - dt1.tick).toBe(1);
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
//#endregion
|
|
333
|
-
|
|
334
|
-
describe("timezoneOffsetMinutes", () => {
|
|
335
|
-
it("returns current timezone offset", () => {
|
|
336
|
-
const dt = new DateTime(2024, 3, 15, 10, 30, 45);
|
|
337
|
-
const expected = new Date().getTimezoneOffset() * -1;
|
|
338
|
-
|
|
339
|
-
expect(dt.timezoneOffsetMinutes).toBe(expected);
|
|
340
|
-
});
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
describe("dayOfWeek", () => {
|
|
344
|
-
it("returns day of week (Sun~Sat: 0~6)", () => {
|
|
345
|
-
// 2024-03-15 is Friday (5)
|
|
346
|
-
const dt = new DateTime(2024, 3, 15);
|
|
347
|
-
|
|
348
|
-
expect(dt.dayOfWeek).toBe(5);
|
|
349
|
-
});
|
|
350
224
|
});
|
|
351
225
|
|
|
352
226
|
describe("isValid", () => {
|
|
@@ -359,25 +233,6 @@ describe("DateTime", () => {
|
|
|
359
233
|
const dt = new DateTime(NaN);
|
|
360
234
|
expect(dt.isValid).toBe(false);
|
|
361
235
|
});
|
|
362
|
-
|
|
363
|
-
it("default constructor is valid datetime", () => {
|
|
364
|
-
const dt = new DateTime();
|
|
365
|
-
expect(dt.isValid).toBe(true);
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
describe("toFormatString()", () => {
|
|
370
|
-
it("yyyy-MM-dd format", () => {
|
|
371
|
-
const dt = new DateTime(2024, 3, 5);
|
|
372
|
-
|
|
373
|
-
expect(dt.toFormatString("yyyy-MM-dd")).toBe("2024-03-05");
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
it("HH:mm:ss format", () => {
|
|
377
|
-
const dt = new DateTime(2024, 3, 5, 9, 5, 3);
|
|
378
|
-
|
|
379
|
-
expect(dt.toFormatString("HH:mm:ss")).toBe("09:05:03");
|
|
380
|
-
});
|
|
381
236
|
});
|
|
382
237
|
|
|
383
238
|
describe("toString()", () => {
|
|
@@ -13,27 +13,6 @@ describe("LazyGcMap", () => {
|
|
|
13
13
|
//#region Basic Map operations
|
|
14
14
|
|
|
15
15
|
describe("Basic Map operations", () => {
|
|
16
|
-
it("Stores and retrieves values with set/get", () => {
|
|
17
|
-
const map = new LazyGcMap<string, number>({
|
|
18
|
-
gcInterval: 1000,
|
|
19
|
-
expireTime: 5000,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
map.set("key1", 100);
|
|
23
|
-
expect(map.get("key1")).toBe(100);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it("Checks key existence with has", () => {
|
|
27
|
-
const map = new LazyGcMap<string, number>({
|
|
28
|
-
gcInterval: 1000,
|
|
29
|
-
expireTime: 5000,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
map.set("key1", 100);
|
|
33
|
-
expect(map.has("key1")).toBe(true);
|
|
34
|
-
expect(map.has("key2")).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
16
|
it("Deletes values with delete", () => {
|
|
38
17
|
const map = new LazyGcMap<string, number>({
|
|
39
18
|
gcInterval: 1000,
|
|
@@ -61,30 +40,6 @@ describe("LazyGcMap", () => {
|
|
|
61
40
|
expect(map.has("key1")).toBe(false);
|
|
62
41
|
expect(map.has("key2")).toBe(false);
|
|
63
42
|
});
|
|
64
|
-
|
|
65
|
-
it("Gets size with size property", () => {
|
|
66
|
-
const map = new LazyGcMap<string, number>({
|
|
67
|
-
gcInterval: 1000,
|
|
68
|
-
expireTime: 5000,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
expect(map.size).toBe(0);
|
|
72
|
-
map.set("key1", 100);
|
|
73
|
-
expect(map.size).toBe(1);
|
|
74
|
-
map.set("key2", 200);
|
|
75
|
-
expect(map.size).toBe(2);
|
|
76
|
-
map.delete("key1");
|
|
77
|
-
expect(map.size).toBe(1);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("Returns undefined for non-existent keys", () => {
|
|
81
|
-
const map = new LazyGcMap<string, number>({
|
|
82
|
-
gcInterval: 1000,
|
|
83
|
-
expireTime: 5000,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(map.get("nonexistent")).toBe(undefined);
|
|
87
|
-
});
|
|
88
43
|
});
|
|
89
44
|
|
|
90
45
|
//#endregion
|
|
@@ -493,22 +448,6 @@ describe("LazyGcMap", () => {
|
|
|
493
448
|
expect(map.get("key2")).toBe(200);
|
|
494
449
|
});
|
|
495
450
|
|
|
496
|
-
it("clear is safe to call multiple times", () => {
|
|
497
|
-
const map = new LazyGcMap<string, number>({
|
|
498
|
-
gcInterval: 1000,
|
|
499
|
-
expireTime: 5000,
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
map.set("key1", 100);
|
|
503
|
-
|
|
504
|
-
// Safe to call multiple times
|
|
505
|
-
map.clear();
|
|
506
|
-
map.clear();
|
|
507
|
-
map.clear();
|
|
508
|
-
|
|
509
|
-
expect(map.size).toBe(0);
|
|
510
|
-
});
|
|
511
|
-
|
|
512
451
|
it("GC works normally after clear", async () => {
|
|
513
452
|
const map = new LazyGcMap<string, number>({
|
|
514
453
|
gcInterval: 100,
|
|
@@ -529,31 +468,6 @@ describe("LazyGcMap", () => {
|
|
|
529
468
|
|
|
530
469
|
//#endregion
|
|
531
470
|
|
|
532
|
-
//#region SharedArrayBuffer support
|
|
533
|
-
|
|
534
|
-
describe("SharedArrayBuffer support", () => {
|
|
535
|
-
it("Can use SharedArrayBuffer as value", () => {
|
|
536
|
-
// SharedArrayBuffer may be disabled for security in some environments
|
|
537
|
-
if (typeof SharedArrayBuffer === "undefined") {
|
|
538
|
-
expect(true).toBe(true); // Skip if not supported
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
const map = new LazyGcMap<string, SharedArrayBuffer>({
|
|
543
|
-
gcInterval: 1000,
|
|
544
|
-
expireTime: 5000,
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
const buffer = new SharedArrayBuffer(16);
|
|
548
|
-
map.set("key1", buffer);
|
|
549
|
-
|
|
550
|
-
expect(map.get("key1")).toBe(buffer);
|
|
551
|
-
expect(map.get("key1")?.byteLength).toBe(16);
|
|
552
|
-
});
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
//#endregion
|
|
556
|
-
|
|
557
471
|
//#region Iterator
|
|
558
472
|
|
|
559
473
|
describe("Iterator", () => {
|