@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.
Files changed (151) hide show
  1. package/README.md +66 -267
  2. package/dist/common.types.d.ts +14 -14
  3. package/dist/errors/argument-error.d.ts +10 -10
  4. package/dist/errors/argument-error.d.ts.map +1 -1
  5. package/dist/errors/argument-error.js +2 -2
  6. package/dist/errors/argument-error.js.map +1 -1
  7. package/dist/errors/not-implemented-error.d.ts +8 -8
  8. package/dist/errors/not-implemented-error.js +2 -2
  9. package/dist/errors/not-implemented-error.js.map +1 -1
  10. package/dist/errors/sd-error.d.ts +10 -10
  11. package/dist/errors/sd-error.d.ts.map +1 -1
  12. package/dist/errors/timeout-error.d.ts +10 -10
  13. package/dist/errors/timeout-error.js +3 -3
  14. package/dist/errors/timeout-error.js.map +1 -1
  15. package/dist/extensions/arr-ext.d.ts +2 -2
  16. package/dist/extensions/arr-ext.helpers.d.ts +8 -8
  17. package/dist/extensions/arr-ext.helpers.js +1 -1
  18. package/dist/extensions/arr-ext.helpers.js.map +1 -1
  19. package/dist/extensions/arr-ext.js +13 -13
  20. package/dist/extensions/arr-ext.js.map +1 -1
  21. package/dist/extensions/arr-ext.types.d.ts +57 -57
  22. package/dist/extensions/arr-ext.types.d.ts.map +1 -1
  23. package/dist/extensions/map-ext.d.ts +16 -16
  24. package/dist/extensions/set-ext.d.ts +11 -11
  25. package/dist/features/debounce-queue.d.ts +17 -15
  26. package/dist/features/debounce-queue.d.ts.map +1 -1
  27. package/dist/features/debounce-queue.js +6 -6
  28. package/dist/features/debounce-queue.js.map +1 -1
  29. package/dist/features/event-emitter.d.ts +20 -20
  30. package/dist/features/event-emitter.js +17 -17
  31. package/dist/features/serial-queue.d.ts +11 -11
  32. package/dist/features/serial-queue.js +5 -5
  33. package/dist/features/serial-queue.js.map +1 -1
  34. package/dist/globals.d.ts +4 -4
  35. package/dist/types/date-only.d.ts +64 -64
  36. package/dist/types/date-only.d.ts.map +1 -1
  37. package/dist/types/date-only.js +63 -63
  38. package/dist/types/date-time.d.ts +37 -37
  39. package/dist/types/date-time.d.ts.map +1 -1
  40. package/dist/types/date-time.js +54 -37
  41. package/dist/types/date-time.js.map +1 -1
  42. package/dist/types/lazy-gc-map.d.ts +26 -26
  43. package/dist/types/lazy-gc-map.d.ts.map +1 -1
  44. package/dist/types/lazy-gc-map.js +26 -26
  45. package/dist/types/lazy-gc-map.js.map +1 -1
  46. package/dist/types/time.d.ts +25 -25
  47. package/dist/types/time.d.ts.map +1 -1
  48. package/dist/types/time.js +25 -25
  49. package/dist/types/time.js.map +1 -1
  50. package/dist/types/uuid.d.ts +11 -11
  51. package/dist/types/uuid.d.ts.map +1 -1
  52. package/dist/types/uuid.js +12 -12
  53. package/dist/types/uuid.js.map +1 -1
  54. package/dist/utils/bytes.d.ts +17 -17
  55. package/dist/utils/bytes.js +4 -4
  56. package/dist/utils/bytes.js.map +1 -1
  57. package/dist/utils/date-format.d.ts +45 -45
  58. package/dist/utils/date-format.js +1 -1
  59. package/dist/utils/date-format.js.map +1 -1
  60. package/dist/utils/error.d.ts +4 -4
  61. package/dist/utils/json.d.ts +17 -17
  62. package/dist/utils/json.js +3 -3
  63. package/dist/utils/json.js.map +1 -1
  64. package/dist/utils/num.d.ts +23 -23
  65. package/dist/utils/obj.d.ts +111 -111
  66. package/dist/utils/obj.d.ts.map +1 -1
  67. package/dist/utils/obj.js +3 -3
  68. package/dist/utils/obj.js.map +1 -1
  69. package/dist/utils/path.d.ts +10 -10
  70. package/dist/utils/primitive.d.ts +5 -5
  71. package/dist/utils/primitive.js +1 -1
  72. package/dist/utils/primitive.js.map +1 -1
  73. package/dist/utils/str.d.ts +46 -46
  74. package/dist/utils/str.d.ts.map +1 -1
  75. package/dist/utils/str.js +5 -5
  76. package/dist/utils/str.js.map +1 -1
  77. package/dist/utils/template-strings.d.ts +26 -26
  78. package/dist/utils/transferable.d.ts +18 -18
  79. package/dist/utils/transferable.js +1 -1
  80. package/dist/utils/transferable.js.map +1 -1
  81. package/dist/utils/wait.d.ts +9 -9
  82. package/dist/utils/xml.d.ts +13 -13
  83. package/dist/utils/xml.d.ts.map +1 -1
  84. package/dist/utils/xml.js +1 -0
  85. package/dist/utils/xml.js.map +1 -1
  86. package/dist/zip/sd-zip.d.ts +22 -22
  87. package/dist/zip/sd-zip.js +16 -16
  88. package/package.json +4 -4
  89. package/src/common.types.ts +17 -17
  90. package/src/errors/argument-error.ts +15 -15
  91. package/src/errors/not-implemented-error.ts +9 -9
  92. package/src/errors/sd-error.ts +12 -12
  93. package/src/errors/timeout-error.ts +12 -12
  94. package/src/extensions/arr-ext.helpers.ts +10 -10
  95. package/src/extensions/arr-ext.ts +57 -57
  96. package/src/extensions/arr-ext.types.ts +59 -59
  97. package/src/extensions/map-ext.ts +16 -16
  98. package/src/extensions/set-ext.ts +11 -11
  99. package/src/features/debounce-queue.ts +21 -19
  100. package/src/features/event-emitter.ts +25 -25
  101. package/src/features/serial-queue.ts +13 -13
  102. package/src/globals.ts +4 -4
  103. package/src/index.ts +1 -1
  104. package/src/types/date-only.ts +83 -83
  105. package/src/types/date-time.ts +64 -44
  106. package/src/types/lazy-gc-map.ts +45 -45
  107. package/src/types/time.ts +34 -34
  108. package/src/types/uuid.ts +17 -17
  109. package/src/utils/bytes.ts +35 -35
  110. package/src/utils/date-format.ts +65 -65
  111. package/src/utils/error.ts +4 -4
  112. package/src/utils/json.ts +39 -39
  113. package/src/utils/num.ts +23 -23
  114. package/src/utils/obj.ts +138 -138
  115. package/src/utils/path.ts +10 -10
  116. package/src/utils/primitive.ts +6 -6
  117. package/src/utils/str.ts +260 -261
  118. package/src/utils/template-strings.ts +29 -29
  119. package/src/utils/transferable.ts +284 -284
  120. package/src/utils/wait.ts +10 -10
  121. package/src/utils/xml.ts +20 -19
  122. package/src/zip/sd-zip.ts +25 -25
  123. package/tests/errors/errors.spec.ts +80 -0
  124. package/tests/extensions/array-extension.spec.ts +796 -0
  125. package/tests/extensions/map-extension.spec.ts +147 -0
  126. package/tests/extensions/set-extension.spec.ts +74 -0
  127. package/tests/types/date-only.spec.ts +638 -0
  128. package/tests/types/date-time.spec.ts +391 -0
  129. package/tests/types/lazy-gc-map.spec.ts +692 -0
  130. package/tests/types/time.spec.ts +559 -0
  131. package/tests/types/uuid.spec.ts +74 -0
  132. package/tests/utils/bytes-utils.spec.ts +230 -0
  133. package/tests/utils/date-format.spec.ts +373 -0
  134. package/tests/utils/debounce-queue.spec.ts +272 -0
  135. package/tests/utils/json.spec.ts +486 -0
  136. package/tests/utils/number.spec.ts +157 -0
  137. package/tests/utils/object.spec.ts +829 -0
  138. package/tests/utils/path.spec.ts +78 -0
  139. package/tests/utils/primitive.spec.ts +43 -0
  140. package/tests/utils/sd-event-emitter.spec.ts +216 -0
  141. package/tests/utils/serial-queue.spec.ts +365 -0
  142. package/tests/utils/string.spec.ts +281 -0
  143. package/tests/utils/template-strings.spec.ts +57 -0
  144. package/tests/utils/transferable.spec.ts +703 -0
  145. package/tests/utils/wait.spec.ts +145 -0
  146. package/tests/utils/xml.spec.ts +146 -0
  147. package/tests/zip/sd-zip.spec.ts +238 -0
  148. package/docs/extensions.md +0 -503
  149. package/docs/features.md +0 -109
  150. package/docs/types.md +0 -486
  151. package/docs/utils.md +0 -780
@@ -0,0 +1,391 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { DateTime } from "@simplysm/core-common";
3
+
4
+ describe("DateTime", () => {
5
+ describe("constructor", () => {
6
+ it("default constructor uses current time", () => {
7
+ const before = Date.now();
8
+ const dt = new DateTime();
9
+ const after = Date.now();
10
+
11
+ expect(dt.tick).toBeGreaterThanOrEqual(before);
12
+ expect(dt.tick).toBeLessThanOrEqual(after);
13
+ });
14
+
15
+ it("creates with year, month, day, hour, minute, second, millisecond", () => {
16
+ const dt = new DateTime(2024, 3, 15, 10, 30, 45, 123);
17
+
18
+ expect(dt.year).toBe(2024);
19
+ expect(dt.month).toBe(3);
20
+ expect(dt.day).toBe(15);
21
+ expect(dt.hour).toBe(10);
22
+ expect(dt.minute).toBe(30);
23
+ expect(dt.second).toBe(45);
24
+ expect(dt.millisecond).toBe(123);
25
+ });
26
+
27
+ it("creates with tick", () => {
28
+ const tick = 1710489045123;
29
+ const dt = new DateTime(tick);
30
+
31
+ expect(dt.tick).toBe(tick);
32
+ });
33
+
34
+ it("creates with Date object", () => {
35
+ const date = new Date(2024, 2, 15, 10, 30, 45, 123);
36
+ const dt = new DateTime(date);
37
+
38
+ expect(dt.year).toBe(2024);
39
+ expect(dt.month).toBe(3);
40
+ expect(dt.day).toBe(15);
41
+ });
42
+
43
+ it("creates leap year February 29th", () => {
44
+ const dt = new DateTime(2024, 2, 29);
45
+
46
+ expect(dt.year).toBe(2024);
47
+ expect(dt.month).toBe(2);
48
+ expect(dt.day).toBe(29);
49
+ expect(dt.isValid).toBe(true);
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
+ });
68
+
69
+ describe("parse()", () => {
70
+ it("parses ISO 8601 format", () => {
71
+ const dt = DateTime.parse("2024-03-15T10:30:45.123Z");
72
+
73
+ expect(dt.year).toBe(2024);
74
+ expect(dt.month).toBe(3);
75
+ expect(dt.day).toBe(15);
76
+ });
77
+
78
+ it("parses yyyy-MM-dd HH:mm:ss format", () => {
79
+ const dt = DateTime.parse("2024-03-15 10:30:45");
80
+
81
+ expect(dt.year).toBe(2024);
82
+ expect(dt.month).toBe(3);
83
+ expect(dt.day).toBe(15);
84
+ expect(dt.hour).toBe(10);
85
+ expect(dt.minute).toBe(30);
86
+ expect(dt.second).toBe(45);
87
+ });
88
+
89
+ it("parses format with milliseconds", () => {
90
+ const dt = DateTime.parse("2024-03-15 10:30:45.123");
91
+
92
+ expect(dt.millisecond).toBe(123);
93
+ });
94
+
95
+ it("pads 1-digit milliseconds to 100ms unit (ISO 8601)", () => {
96
+ const dt = DateTime.parse("2024-03-15 10:30:45.1");
97
+
98
+ expect(dt.millisecond).toBe(100);
99
+ });
100
+
101
+ it("pads 2-digit milliseconds to 10ms unit (ISO 8601)", () => {
102
+ const dt = DateTime.parse("2024-03-15 10:30:45.01");
103
+
104
+ expect(dt.millisecond).toBe(10);
105
+ });
106
+
107
+ it("parses 3-digit milliseconds as-is", () => {
108
+ const dt = DateTime.parse("2024-03-15 10:30:45.001");
109
+
110
+ expect(dt.millisecond).toBe(1);
111
+ });
112
+
113
+ it("parses yyyyMMddHHmmss format", () => {
114
+ const dt = DateTime.parse("20240315103045");
115
+
116
+ expect(dt.year).toBe(2024);
117
+ expect(dt.month).toBe(3);
118
+ expect(dt.day).toBe(15);
119
+ expect(dt.hour).toBe(10);
120
+ expect(dt.minute).toBe(30);
121
+ expect(dt.second).toBe(45);
122
+ });
123
+
124
+ it("parses Korean AM/PM format", () => {
125
+ const dtAm = DateTime.parse("2024-03-15 오전 10:30:45");
126
+ expect(dtAm.hour).toBe(10);
127
+
128
+ const dtPm = DateTime.parse("2024-03-15 오후 02:30:45");
129
+ expect(dtPm.hour).toBe(14);
130
+ });
131
+
132
+ it("PM 12:00:00 is noon (12 o'clock)", () => {
133
+ const dt = DateTime.parse("2024-03-15 오후 12:00:00");
134
+
135
+ expect(dt.hour).toBe(12);
136
+ expect(dt.minute).toBe(0);
137
+ expect(dt.second).toBe(0);
138
+ });
139
+
140
+ it("AM 12:00:00 is midnight (0 o'clock)", () => {
141
+ const dt = DateTime.parse("2024-03-15 오전 12:00:00");
142
+
143
+ expect(dt.hour).toBe(0);
144
+ expect(dt.minute).toBe(0);
145
+ expect(dt.second).toBe(0);
146
+ });
147
+
148
+ it("PM 12:30:45 is after noon (12:30:45)", () => {
149
+ const dt = DateTime.parse("2024-03-15 오후 12:30:45");
150
+
151
+ expect(dt.hour).toBe(12);
152
+ expect(dt.minute).toBe(30);
153
+ expect(dt.second).toBe(45);
154
+ });
155
+
156
+ it("AM 12:30:45 is after midnight (0:30:45)", () => {
157
+ const dt = DateTime.parse("2024-03-15 오전 12:30:45");
158
+
159
+ expect(dt.hour).toBe(0);
160
+ expect(dt.minute).toBe(30);
161
+ expect(dt.second).toBe(45);
162
+ });
163
+
164
+ it("throws error for invalid format", () => {
165
+ expect(() => DateTime.parse("invalid")).toThrow();
166
+ });
167
+ });
168
+
169
+ describe("Immutability", () => {
170
+ it("setYear returns new instance", () => {
171
+ const dt1 = new DateTime(2024, 3, 15);
172
+ const dt2 = dt1.setYear(2025);
173
+
174
+ expect(dt1.year).toBe(2024);
175
+ expect(dt2.year).toBe(2025);
176
+ expect(dt1).not.toBe(dt2);
177
+ });
178
+
179
+ it("setMonth returns new instance", () => {
180
+ const dt1 = new DateTime(2024, 3, 15);
181
+ const dt2 = dt1.setMonth(6);
182
+
183
+ expect(dt1.month).toBe(3);
184
+ expect(dt2.month).toBe(6);
185
+ });
186
+
187
+ it("setMonth adjusts to last day of target month", () => {
188
+ // January 31st → February (adjusted to 28th or 29th)
189
+ const dt1 = new DateTime(2024, 1, 31);
190
+ const dt2 = dt1.setMonth(2);
191
+
192
+ expect(dt2.month).toBe(2);
193
+ expect(dt2.day).toBe(29); // 2024 is leap year
194
+ });
195
+
196
+ it("setMonth(13) returns next year January", () => {
197
+ const dt = new DateTime(2024, 6, 15);
198
+ const result = dt.setMonth(13);
199
+
200
+ expect(result.year).toBe(2025);
201
+ expect(result.month).toBe(1);
202
+ expect(result.day).toBe(15);
203
+ });
204
+
205
+ it("setMonth(0) returns previous year December", () => {
206
+ const dt = new DateTime(2024, 6, 15);
207
+ const result = dt.setMonth(0);
208
+
209
+ expect(result.year).toBe(2023);
210
+ expect(result.month).toBe(12);
211
+ expect(result.day).toBe(15);
212
+ });
213
+
214
+ it("setMonth(-1) returns previous year November", () => {
215
+ const dt = new DateTime(2024, 6, 15);
216
+ const result = dt.setMonth(-1);
217
+
218
+ expect(result.year).toBe(2023);
219
+ expect(result.month).toBe(11);
220
+ expect(result.day).toBe(15);
221
+ });
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
+ });
241
+
242
+ 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
+ it("addDays", () => {
259
+ const dt1 = new DateTime(2024, 3, 15);
260
+ const dt2 = dt1.addDays(20);
261
+
262
+ expect(dt2.month).toBe(4);
263
+ expect(dt2.day).toBe(4);
264
+ });
265
+
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
+ it("addMinutes", () => {
274
+ const dt1 = new DateTime(2024, 3, 15, 10, 30);
275
+ const dt2 = dt1.addMinutes(45);
276
+
277
+ expect(dt2.hour).toBe(11);
278
+ expect(dt2.minute).toBe(15);
279
+ });
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
+ });
351
+
352
+ describe("isValid", () => {
353
+ it("valid datetime returns true", () => {
354
+ const dt = new DateTime(2024, 3, 15, 10, 30, 45);
355
+ expect(dt.isValid).toBe(true);
356
+ });
357
+
358
+ it("invalid datetime returns false", () => {
359
+ const dt = new DateTime(NaN);
360
+ expect(dt.isValid).toBe(false);
361
+ });
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
+ });
382
+
383
+ describe("toString()", () => {
384
+ it("returns ISO 8601 format", () => {
385
+ const dt = new DateTime(2024, 3, 15, 10, 30, 45, 123);
386
+ const str = dt.toString();
387
+
388
+ expect(str).toMatch(/^2024-03-15T10:30:45\.123[+-]\d{2}:\d{2}$/);
389
+ });
390
+ });
391
+ });