@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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import "./map-ext";
|
|
8
|
-
import {
|
|
8
|
+
import { clone, equal, merge } from "../utils/obj";
|
|
9
9
|
import type { PrimitiveTypeStr, Type } from "../common.types";
|
|
10
10
|
import { DateTime } from "../types/date-time";
|
|
11
11
|
import { DateOnly } from "../types/date-only";
|
|
@@ -13,12 +13,12 @@ import { Time } from "../types/time";
|
|
|
13
13
|
import { Uuid } from "../types/uuid";
|
|
14
14
|
import { ArgumentError } from "../errors/argument-error";
|
|
15
15
|
import { SdError } from "../errors/sd-error";
|
|
16
|
-
import { compareForOrder } from "./arr-ext.helpers";
|
|
16
|
+
import { compareForOrder, getDistinctIndices } from "./arr-ext.helpers";
|
|
17
17
|
import type {
|
|
18
18
|
ReadonlyArrayExt,
|
|
19
19
|
MutableArrayExt,
|
|
20
20
|
ArrayDiffsResult,
|
|
21
|
-
|
|
21
|
+
ArrayOneWayDiffResult,
|
|
22
22
|
TreeArray,
|
|
23
23
|
} from "./arr-ext.types";
|
|
24
24
|
|
|
@@ -155,7 +155,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
// Object keys use the existing approach O(n²)
|
|
158
|
-
const existsRecord = result.find((item) =>
|
|
158
|
+
const existsRecord = result.find((item) => equal(item.key, keyObj));
|
|
159
159
|
if (existsRecord !== undefined) {
|
|
160
160
|
existsRecord.values.push(valueObj);
|
|
161
161
|
} else {
|
|
@@ -298,7 +298,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
298
298
|
|
|
299
299
|
const fn = (items: T[]): TreeArray<T>[] => {
|
|
300
300
|
return items.map((item) => ({
|
|
301
|
-
...
|
|
301
|
+
...clone(item),
|
|
302
302
|
children: fn(childrenMap.get(item[key]) ?? []),
|
|
303
303
|
}));
|
|
304
304
|
};
|
|
@@ -310,66 +310,8 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
310
310
|
distinct<T>(
|
|
311
311
|
options?: boolean | { matchAddress?: boolean; keyFn?: (item: T) => string | number },
|
|
312
312
|
): T[] {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
// matchAddress: Set-based O(n)
|
|
317
|
-
if (opts.matchAddress === true) return [...new Set(this)];
|
|
318
|
-
|
|
319
|
-
// keyFn provided: custom key-based O(n)
|
|
320
|
-
if (opts.keyFn) {
|
|
321
|
-
const seen = new Set<string | number>();
|
|
322
|
-
const result: T[] = [];
|
|
323
|
-
for (const item of this) {
|
|
324
|
-
const key = opts.keyFn(item);
|
|
325
|
-
if (!seen.has(key)) {
|
|
326
|
-
seen.add(key);
|
|
327
|
-
result.push(item);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
return result;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Default: type-based processing
|
|
334
|
-
const seen = new Map<string, T>();
|
|
335
|
-
const seenRefs = new Set<symbol | ((...args: unknown[]) => unknown)>(); // O(n) processing for symbol/function
|
|
336
|
-
const result: T[] = [];
|
|
337
|
-
|
|
338
|
-
for (const item of this) {
|
|
339
|
-
// primitive types take the fast path
|
|
340
|
-
if (item === null || typeof item !== "object") {
|
|
341
|
-
const type = typeof item;
|
|
342
|
-
|
|
343
|
-
// symbol, function use Set for identity comparison (O(n))
|
|
344
|
-
if (type === "symbol" || type === "function") {
|
|
345
|
-
if (!seenRefs.has(item)) {
|
|
346
|
-
seenRefs.add(item);
|
|
347
|
-
result.push(item);
|
|
348
|
-
}
|
|
349
|
-
continue;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// Other primitives: type prefix + special case handling
|
|
353
|
-
let key = type + ":";
|
|
354
|
-
if (Object.is(item, -0)) {
|
|
355
|
-
key += "-0";
|
|
356
|
-
} else {
|
|
357
|
-
key += String(item);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (!seen.has(key)) {
|
|
361
|
-
seen.set(key, item);
|
|
362
|
-
result.push(item);
|
|
363
|
-
}
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (!result.some((item1) => objEqual(item1, item))) {
|
|
368
|
-
result.push(item);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return result;
|
|
313
|
+
const keptIndices = getDistinctIndices(this, options);
|
|
314
|
+
return Array.from(keptIndices).map((i) => this[i]);
|
|
373
315
|
},
|
|
374
316
|
|
|
375
317
|
orderBy<T>(
|
|
@@ -432,7 +374,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
432
374
|
// Skip already matched items using Set-based skipping (avoid O(n) splice removal)
|
|
433
375
|
for (const targetItem of uncheckedTarget) {
|
|
434
376
|
if (!uncheckedTargetSet.has(targetItem)) continue;
|
|
435
|
-
if (
|
|
377
|
+
if (equal(targetItem, sourceItem, excludeOpts)) {
|
|
436
378
|
sameTarget = targetItem;
|
|
437
379
|
break;
|
|
438
380
|
}
|
|
@@ -475,7 +417,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
475
417
|
excludes?: string[];
|
|
476
418
|
includes?: string[];
|
|
477
419
|
},
|
|
478
|
-
):
|
|
420
|
+
): ArrayOneWayDiffResult<T>[] {
|
|
479
421
|
const orgItemMap =
|
|
480
422
|
orgItems instanceof Map
|
|
481
423
|
? orgItems
|
|
@@ -486,7 +428,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
486
428
|
);
|
|
487
429
|
const includeSame = options?.includeSame ?? false;
|
|
488
430
|
|
|
489
|
-
const diffs:
|
|
431
|
+
const diffs: ArrayOneWayDiffResult<T>[] = [];
|
|
490
432
|
for (const item of this) {
|
|
491
433
|
const keyValue =
|
|
492
434
|
typeof keyPropNameOrGetValFn === "function"
|
|
@@ -504,7 +446,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
504
446
|
}
|
|
505
447
|
|
|
506
448
|
if (
|
|
507
|
-
|
|
449
|
+
equal(orgItem, item, {
|
|
508
450
|
topLevelExcludes: options?.excludes,
|
|
509
451
|
topLevelIncludes: options?.includes,
|
|
510
452
|
})
|
|
@@ -527,9 +469,9 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
527
469
|
excludes?: string[];
|
|
528
470
|
},
|
|
529
471
|
): (T | P | (T & P))[] {
|
|
530
|
-
const diffs = this.diffs(target, options);
|
|
472
|
+
const diffs = this.diffs(target as any[], options as any);
|
|
531
473
|
|
|
532
|
-
const result: (T | P | (T & P))[] =
|
|
474
|
+
const result: (T | P | (T & P))[] = clone(this);
|
|
533
475
|
|
|
534
476
|
// Pre-calculate original index of source items to improve O(n) lookup to O(1)
|
|
535
477
|
const sourceIndexMap = new Map<T, number>();
|
|
@@ -544,7 +486,7 @@ const arrayReadonlyExtensions: ReadonlyArrayExt<any> & ThisType<any[]> = {
|
|
|
544
486
|
if (sourceIndex === undefined) {
|
|
545
487
|
throw new SdError("Unexpected error: source item not found in merge.");
|
|
546
488
|
}
|
|
547
|
-
result[sourceIndex] =
|
|
489
|
+
result[sourceIndex] = merge(diff.source, diff.target);
|
|
548
490
|
}
|
|
549
491
|
// When adding
|
|
550
492
|
else if (diff.target !== undefined) {
|
|
@@ -622,107 +564,17 @@ const arrayMutableExtensions: MutableArrayExt<any> & ThisType<any[]> = {
|
|
|
622
564
|
distinctThis<T>(
|
|
623
565
|
options?: boolean | { matchAddress?: boolean; keyFn?: (item: T) => string | number },
|
|
624
566
|
): T[] {
|
|
625
|
-
|
|
626
|
-
const
|
|
627
|
-
|
|
628
|
-
// matchAddress: Set-based O(n)
|
|
629
|
-
// To preserve first occurrence, collect indices to remove after forward traversal
|
|
630
|
-
if (opts.matchAddress === true) {
|
|
631
|
-
const seen = new Set<T>();
|
|
632
|
-
const toRemove: number[] = [];
|
|
633
|
-
for (let i = 0; i < this.length; i++) {
|
|
634
|
-
if (seen.has(this[i])) {
|
|
635
|
-
toRemove.push(i);
|
|
636
|
-
} else {
|
|
637
|
-
seen.add(this[i]);
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
// Remove in reverse order (prevent index changes)
|
|
641
|
-
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
642
|
-
this.splice(toRemove[i], 1);
|
|
643
|
-
}
|
|
644
|
-
return this;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// keyFn provided: custom key-based O(n)
|
|
648
|
-
// To preserve first occurrence, collect indices to remove after forward traversal
|
|
649
|
-
if (opts.keyFn) {
|
|
650
|
-
const seen = new Set<string | number>();
|
|
651
|
-
const toRemove: number[] = [];
|
|
652
|
-
for (let i = 0; i < this.length; i++) {
|
|
653
|
-
const key = opts.keyFn(this[i]);
|
|
654
|
-
if (seen.has(key)) {
|
|
655
|
-
toRemove.push(i);
|
|
656
|
-
} else {
|
|
657
|
-
seen.add(key);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
// Remove in reverse order (prevent index changes)
|
|
661
|
-
for (let i = toRemove.length - 1; i >= 0; i--) {
|
|
662
|
-
this.splice(toRemove[i], 1);
|
|
663
|
-
}
|
|
664
|
-
return this;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// Default: type-based processing (primitive optimization)
|
|
668
|
-
const seen = new Map<string, T>();
|
|
669
|
-
const seenRefs = new Set<symbol | ((...args: unknown[]) => unknown)>();
|
|
670
|
-
const toRemoveSet = new Set<number>();
|
|
671
|
-
|
|
567
|
+
const keptIndices = getDistinctIndices(this, options);
|
|
568
|
+
const indicesToRemove = [];
|
|
672
569
|
for (let i = 0; i < this.length; i++) {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
// primitive types take the fast path O(n)
|
|
676
|
-
if (item === null || typeof item !== "object") {
|
|
677
|
-
const type = typeof item;
|
|
678
|
-
|
|
679
|
-
// symbol, function use Set for identity comparison
|
|
680
|
-
if (type === "symbol" || type === "function") {
|
|
681
|
-
if (seenRefs.has(item)) {
|
|
682
|
-
toRemoveSet.add(i);
|
|
683
|
-
} else {
|
|
684
|
-
seenRefs.add(item);
|
|
685
|
-
}
|
|
686
|
-
continue;
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// Other primitives: type prefix + special case handling
|
|
690
|
-
let key = type + ":";
|
|
691
|
-
if (Object.is(item, -0)) {
|
|
692
|
-
key += "-0";
|
|
693
|
-
} else {
|
|
694
|
-
key += String(item);
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
if (seen.has(key)) {
|
|
698
|
-
toRemoveSet.add(i);
|
|
699
|
-
} else {
|
|
700
|
-
seen.set(key, item);
|
|
701
|
-
}
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// Objects: deep comparison O(n²) - compare with previous non-removed items
|
|
706
|
-
let hasDuplicateBefore = false;
|
|
707
|
-
for (let j = 0; j < i; j++) {
|
|
708
|
-
// Skip indices in toRemoveSet (O(1) lookup)
|
|
709
|
-
if (toRemoveSet.has(j)) continue;
|
|
710
|
-
if (objEqual(this[j], item)) {
|
|
711
|
-
hasDuplicateBefore = true;
|
|
712
|
-
break;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
if (hasDuplicateBefore) {
|
|
716
|
-
toRemoveSet.add(i);
|
|
570
|
+
if (!keptIndices.has(i)) {
|
|
571
|
+
indicesToRemove.push(i);
|
|
717
572
|
}
|
|
718
573
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
for (const idx of toRemoveArr) {
|
|
723
|
-
this.splice(idx, 1);
|
|
574
|
+
// Remove in reverse order to prevent index shifts
|
|
575
|
+
for (let i = indicesToRemove.length - 1; i >= 0; i--) {
|
|
576
|
+
this.splice(indicesToRemove[i], 1);
|
|
724
577
|
}
|
|
725
|
-
|
|
726
578
|
return this;
|
|
727
579
|
},
|
|
728
580
|
|
|
@@ -806,7 +658,7 @@ declare global {
|
|
|
806
658
|
|
|
807
659
|
export type {
|
|
808
660
|
ArrayDiffsResult,
|
|
809
|
-
|
|
661
|
+
ArrayOneWayDiffResult,
|
|
810
662
|
TreeArray,
|
|
811
663
|
ComparableType,
|
|
812
664
|
} from "./arr-ext.types";
|
|
@@ -39,33 +39,33 @@ export interface ReadonlyArrayExt<TItem> {
|
|
|
39
39
|
filterExists(): NonNullable<TItem>[];
|
|
40
40
|
|
|
41
41
|
/** Filter only elements of specific type (PrimitiveTypeStr or constructor type) */
|
|
42
|
-
ofType<
|
|
43
|
-
ofType<
|
|
42
|
+
ofType<TKey extends PrimitiveTypeStr>(type: TKey): Extract<TItem, PrimitiveTypeMap[TKey]>[];
|
|
43
|
+
ofType<TNarrow extends TItem>(type: Type<TNarrow>): TNarrow[];
|
|
44
44
|
|
|
45
45
|
/** Async mapping (sequential execution) */
|
|
46
|
-
mapAsync<
|
|
46
|
+
mapAsync<TResult>(selector: (item: TItem, index: number) => Promise<TResult>): Promise<TResult[]>;
|
|
47
47
|
|
|
48
48
|
/** Flatten nested array */
|
|
49
49
|
mapMany(): TItem extends readonly (infer U)[] ? U[] : TItem;
|
|
50
50
|
|
|
51
51
|
/** Map and then flatten */
|
|
52
|
-
mapMany<
|
|
52
|
+
mapMany<TResult>(selector: (item: TItem, index: number) => TResult[]): TResult[];
|
|
53
53
|
|
|
54
54
|
/** Async mapping and then flatten (sequential execution) */
|
|
55
|
-
mapManyAsync<
|
|
55
|
+
mapManyAsync<TResult>(selector: (item: TItem, index: number) => Promise<TResult[]>): Promise<TResult[]>;
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* Async parallel processing (using Promise.all)
|
|
59
59
|
* @note If any rejects, entire operation fail-fast rejects (Promise.all behavior)
|
|
60
60
|
*/
|
|
61
|
-
parallelAsync<
|
|
61
|
+
parallelAsync<TResult>(fn: (item: TItem, index: number) => Promise<TResult>): Promise<TResult[]>;
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
64
|
* Group by key
|
|
65
65
|
* @param keySelector Key selection function for group
|
|
66
66
|
* @note O(n²) complexity (deep comparison for object key support). If only primitive keys are needed, toArrayMap() is more efficient at O(n)
|
|
67
67
|
*/
|
|
68
|
-
groupBy<
|
|
68
|
+
groupBy<TKey>(keySelector: (item: TItem, index: number) => TKey): { key: TKey; values: TItem[] }[];
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* Group by key (with value transformation)
|
|
@@ -73,52 +73,52 @@ export interface ReadonlyArrayExt<TItem> {
|
|
|
73
73
|
* @param valueSelector Value transformation function
|
|
74
74
|
* @note O(n²) complexity (deep comparison for object key support). If only primitive keys are needed, toArrayMap() is more efficient at O(n)
|
|
75
75
|
*/
|
|
76
|
-
groupBy<
|
|
77
|
-
keySelector: (item: TItem, index: number) =>
|
|
78
|
-
valueSelector: (item: TItem, index: number) =>
|
|
76
|
+
groupBy<TKey, TValue>(
|
|
77
|
+
keySelector: (item: TItem, index: number) => TKey,
|
|
78
|
+
valueSelector: (item: TItem, index: number) => TValue,
|
|
79
79
|
): {
|
|
80
|
-
key:
|
|
81
|
-
values:
|
|
80
|
+
key: TKey;
|
|
81
|
+
values: TValue[];
|
|
82
82
|
}[];
|
|
83
83
|
|
|
84
|
-
toMap<
|
|
84
|
+
toMap<TKey>(keySelector: (item: TItem, index: number) => TKey): Map<TKey, TItem>;
|
|
85
85
|
|
|
86
|
-
toMap<
|
|
87
|
-
keySelector: (item: TItem, index: number) =>
|
|
88
|
-
valueSelector: (item: TItem, index: number) =>
|
|
89
|
-
): Map<
|
|
86
|
+
toMap<TKey, TValue>(
|
|
87
|
+
keySelector: (item: TItem, index: number) => TKey,
|
|
88
|
+
valueSelector: (item: TItem, index: number) => TValue,
|
|
89
|
+
): Map<TKey, TValue>;
|
|
90
90
|
|
|
91
|
-
toMapAsync<
|
|
91
|
+
toMapAsync<TKey>(keySelector: (item: TItem, index: number) => Promise<TKey>): Promise<Map<TKey, TItem>>;
|
|
92
92
|
|
|
93
|
-
toMapAsync<
|
|
94
|
-
keySelector: (item: TItem, index: number) => Promise<
|
|
95
|
-
valueSelector: (item: TItem, index: number) => Promise<
|
|
96
|
-
): Promise<Map<
|
|
93
|
+
toMapAsync<TKey, TValue>(
|
|
94
|
+
keySelector: (item: TItem, index: number) => Promise<TKey> | TKey,
|
|
95
|
+
valueSelector: (item: TItem, index: number) => Promise<TValue> | TValue,
|
|
96
|
+
): Promise<Map<TKey, TValue>>;
|
|
97
97
|
|
|
98
|
-
toArrayMap<
|
|
98
|
+
toArrayMap<TKey>(keySelector: (item: TItem, index: number) => TKey): Map<TKey, TItem[]>;
|
|
99
99
|
|
|
100
|
-
toArrayMap<
|
|
101
|
-
keySelector: (item: TItem, index: number) =>
|
|
102
|
-
valueSelector: (item: TItem, index: number) =>
|
|
103
|
-
): Map<
|
|
100
|
+
toArrayMap<TKey, TValue>(
|
|
101
|
+
keySelector: (item: TItem, index: number) => TKey,
|
|
102
|
+
valueSelector: (item: TItem, index: number) => TValue,
|
|
103
|
+
): Map<TKey, TValue[]>;
|
|
104
104
|
|
|
105
|
-
toSetMap<
|
|
106
|
-
toSetMap<
|
|
107
|
-
keySelector: (item: TItem, index: number) =>
|
|
108
|
-
valueSelector: (item: TItem, index: number) =>
|
|
109
|
-
): Map<
|
|
105
|
+
toSetMap<TKey>(keySelector: (item: TItem, index: number) => TKey): Map<TKey, Set<TItem>>;
|
|
106
|
+
toSetMap<TKey, TValue>(
|
|
107
|
+
keySelector: (item: TItem, index: number) => TKey,
|
|
108
|
+
valueSelector: (item: TItem, index: number) => TValue,
|
|
109
|
+
): Map<TKey, Set<TValue>>;
|
|
110
110
|
|
|
111
|
-
toMapValues<
|
|
112
|
-
keySelector: (item: TItem, index: number) =>
|
|
113
|
-
valueSelector: (items: TItem[]) =>
|
|
114
|
-
): Map<
|
|
111
|
+
toMapValues<TKey, TValue>(
|
|
112
|
+
keySelector: (item: TItem, index: number) => TKey,
|
|
113
|
+
valueSelector: (items: TItem[]) => TValue,
|
|
114
|
+
): Map<TKey, TValue>;
|
|
115
115
|
|
|
116
116
|
toObject(keySelector: (item: TItem, index: number) => string): Record<string, TItem>;
|
|
117
117
|
|
|
118
|
-
toObject<
|
|
118
|
+
toObject<TValue>(
|
|
119
119
|
keySelector: (item: TItem, index: number) => string,
|
|
120
|
-
valueSelector: (item: TItem, index: number) =>
|
|
121
|
-
): Record<string,
|
|
120
|
+
valueSelector: (item: TItem, index: number) => TValue,
|
|
121
|
+
): Record<string, TValue>;
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* Convert flat array to tree structure
|
|
@@ -186,22 +186,50 @@ export interface ReadonlyArrayExt<TItem> {
|
|
|
186
186
|
*/
|
|
187
187
|
diffs<TOtherItem>(
|
|
188
188
|
target: TOtherItem[],
|
|
189
|
-
options?: { keys?: string[]; excludes?: string[] },
|
|
190
189
|
): ArrayDiffsResult<TItem, TOtherItem>[];
|
|
191
190
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
diffs<TOtherItem extends Record<string, unknown> = Record<string, unknown>>(
|
|
192
|
+
target: TOtherItem[],
|
|
193
|
+
options: {
|
|
194
|
+
keys: ((keyof TItem | keyof TOtherItem) & string)[];
|
|
195
|
+
excludes?: ((keyof TItem | keyof TOtherItem) & string)[];
|
|
196
|
+
},
|
|
197
|
+
): ArrayDiffsResult<TItem, TOtherItem>[];
|
|
198
|
+
|
|
199
|
+
diffs<TOtherItem extends Record<string, unknown> = Record<string, unknown>>(
|
|
200
|
+
target: TOtherItem[],
|
|
201
|
+
options: {
|
|
202
|
+
excludes: ((keyof TItem | keyof TOtherItem) & string)[];
|
|
203
|
+
},
|
|
204
|
+
): ArrayDiffsResult<TItem, TOtherItem>[];
|
|
205
|
+
|
|
206
|
+
oneWayDiffs<TKey extends keyof TItem>(
|
|
207
|
+
orgItems: TItem[] | Map<TItem[TKey], TItem>,
|
|
208
|
+
keyPropNameOrGetValFn: TKey | ((item: TItem) => string | number | undefined),
|
|
195
209
|
options?: {
|
|
196
210
|
includeSame?: boolean;
|
|
197
211
|
excludes?: string[];
|
|
198
212
|
includes?: string[];
|
|
199
213
|
},
|
|
200
|
-
):
|
|
214
|
+
): ArrayOneWayDiffResult<TItem>[];
|
|
201
215
|
|
|
202
216
|
merge<TOtherItem>(
|
|
203
217
|
target: TOtherItem[],
|
|
204
|
-
|
|
218
|
+
): (TItem | TOtherItem | (TItem & TOtherItem))[];
|
|
219
|
+
|
|
220
|
+
merge<TOtherItem extends Record<string, unknown> = Record<string, unknown>>(
|
|
221
|
+
target: TOtherItem[],
|
|
222
|
+
options: {
|
|
223
|
+
keys: ((keyof TItem | keyof TOtherItem) & string)[];
|
|
224
|
+
excludes?: ((keyof TItem | keyof TOtherItem) & string)[];
|
|
225
|
+
},
|
|
226
|
+
): (TItem | TOtherItem | (TItem & TOtherItem))[];
|
|
227
|
+
|
|
228
|
+
merge<TOtherItem extends Record<string, unknown> = Record<string, unknown>>(
|
|
229
|
+
target: TOtherItem[],
|
|
230
|
+
options: {
|
|
231
|
+
excludes: ((keyof TItem | keyof TOtherItem) & string)[];
|
|
232
|
+
},
|
|
205
233
|
): (TItem | TOtherItem | (TItem & TOtherItem))[];
|
|
206
234
|
|
|
207
235
|
/**
|
|
@@ -213,11 +241,11 @@ export interface ReadonlyArrayExt<TItem> {
|
|
|
213
241
|
|
|
214
242
|
min(): TItem extends number | string ? TItem | undefined : never;
|
|
215
243
|
|
|
216
|
-
min<
|
|
244
|
+
min<TProp extends number | string>(selector?: (item: TItem, index: number) => TProp): TProp | undefined;
|
|
217
245
|
|
|
218
246
|
max(): TItem extends number | string ? TItem | undefined : never;
|
|
219
247
|
|
|
220
|
-
max<
|
|
248
|
+
max<TProp extends number | string>(selector?: (item: TItem, index: number) => TProp): TProp | undefined;
|
|
221
249
|
|
|
222
250
|
shuffle(): TItem[];
|
|
223
251
|
}
|
|
@@ -272,7 +300,7 @@ export type ArrayDiffsResult<TOriginal, TOther> =
|
|
|
272
300
|
| { source: TOriginal; target: undefined } // DELETE
|
|
273
301
|
| { source: TOriginal; target: TOther }; // UPDATE
|
|
274
302
|
|
|
275
|
-
export type
|
|
303
|
+
export type ArrayOneWayDiffResult<TItem> =
|
|
276
304
|
| { type: "create"; item: TItem; orgItem: undefined }
|
|
277
305
|
| { type: "update"; item: TItem; orgItem: TItem }
|
|
278
306
|
| { type: "same"; item: TItem; orgItem: TItem };
|
|
@@ -57,10 +57,10 @@ declare global {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
Object.defineProperty(Map.prototype, "getOrCreate", {
|
|
60
|
-
value: function <
|
|
60
|
+
value: function <TKey, TValue>(this: Map<TKey, TValue>, key: TKey, newValue: TValue | (() => TValue)): TValue {
|
|
61
61
|
if (!this.has(key)) {
|
|
62
62
|
if (typeof newValue === "function") {
|
|
63
|
-
this.set(key, (newValue as () =>
|
|
63
|
+
this.set(key, (newValue as () => TValue)());
|
|
64
64
|
} else {
|
|
65
65
|
this.set(key, newValue);
|
|
66
66
|
}
|
|
@@ -73,7 +73,7 @@ Object.defineProperty(Map.prototype, "getOrCreate", {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
Object.defineProperty(Map.prototype, "update", {
|
|
76
|
-
value: function <
|
|
76
|
+
value: function <TKey, TValue>(this: Map<TKey, TValue>, key: TKey, updateFn: (v: TValue | undefined) => TValue): void {
|
|
77
77
|
const val = this.get(key);
|
|
78
78
|
const res = updateFn(val);
|
|
79
79
|
this.set(key, res);
|
|
@@ -36,7 +36,7 @@ declare global {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
Object.defineProperty(Set.prototype, "adds", {
|
|
39
|
-
value: function <
|
|
39
|
+
value: function <TItem>(this: Set<TItem>, ...values: TItem[]): Set<TItem> {
|
|
40
40
|
for (const val of values) {
|
|
41
41
|
this.add(val);
|
|
42
42
|
}
|
|
@@ -48,7 +48,7 @@ Object.defineProperty(Set.prototype, "adds", {
|
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
Object.defineProperty(Set.prototype, "toggle", {
|
|
51
|
-
value: function <
|
|
51
|
+
value: function <TItem>(this: Set<TItem>, value: TItem, addOrDel?: "add" | "del"): Set<TItem> {
|
|
52
52
|
if (addOrDel === "add") {
|
|
53
53
|
this.add(value);
|
|
54
54
|
} else if (addOrDel === "del") {
|
|
@@ -35,7 +35,7 @@ export class EventEmitter<
|
|
|
35
35
|
* @param listener Event handler
|
|
36
36
|
* @note Duplicate registration of the same listener to the same event is ignored
|
|
37
37
|
*/
|
|
38
|
-
on<
|
|
38
|
+
on<TEventName extends keyof TEvents & string>(type: TEventName, listener: (data: TEvents[TEventName]) => void): void {
|
|
39
39
|
// Get or create map for event type
|
|
40
40
|
let typeMap = this._listenerMap.get(type);
|
|
41
41
|
if (!typeMap) {
|
|
@@ -57,7 +57,7 @@ export class EventEmitter<
|
|
|
57
57
|
* @param type Event type
|
|
58
58
|
* @param listener Event handler to remove
|
|
59
59
|
*/
|
|
60
|
-
off<
|
|
60
|
+
off<TEventName extends keyof TEvents & string>(type: TEventName, listener: (data: TEvents[TEventName]) => void): void {
|
|
61
61
|
const typeMap = this._listenerMap.get(type);
|
|
62
62
|
if (!typeMap) return;
|
|
63
63
|
|
|
@@ -79,9 +79,9 @@ export class EventEmitter<
|
|
|
79
79
|
* @param type Event type
|
|
80
80
|
* @param args Event data (omitted if void type)
|
|
81
81
|
*/
|
|
82
|
-
emit<
|
|
83
|
-
type:
|
|
84
|
-
...args: TEvents[
|
|
82
|
+
emit<TEventName extends keyof TEvents & string>(
|
|
83
|
+
type: TEventName,
|
|
84
|
+
...args: TEvents[TEventName] extends void ? [] : [data: TEvents[TEventName]]
|
|
85
85
|
): void {
|
|
86
86
|
this._target.dispatchEvent(new CustomEvent(type, { detail: args[0] }));
|
|
87
87
|
}
|
|
@@ -92,7 +92,7 @@ export class EventEmitter<
|
|
|
92
92
|
* @param type Event type
|
|
93
93
|
* @returns Number of registered listeners
|
|
94
94
|
*/
|
|
95
|
-
listenerCount<
|
|
95
|
+
listenerCount<TEventName extends keyof TEvents & string>(type: TEventName): number {
|
|
96
96
|
return this._listenerMap.get(type)?.size ?? 0;
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { SdError } from "../errors/sd-error";
|
|
19
19
|
import { EventEmitter } from "./event-emitter";
|
|
20
20
|
import consola from "consola";
|
|
21
|
-
import {
|
|
21
|
+
import { time } from "../utils/wait";
|
|
22
22
|
|
|
23
23
|
interface SerialQueueEvents {
|
|
24
24
|
error: SdError;
|
|
@@ -84,7 +84,7 @@ export class SerialQueue extends EventEmitter<SerialQueueEvents> {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
if (this._gap > 0 && this._queue.length > 0) {
|
|
87
|
-
await
|
|
87
|
+
await time(this._gap);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
} finally {
|
package/src/index.ts
CHANGED
|
@@ -31,24 +31,24 @@ export * from "./features/serial-queue";
|
|
|
31
31
|
export * from "./features/event-emitter";
|
|
32
32
|
//#endregion
|
|
33
33
|
|
|
34
|
-
//#region utils
|
|
35
|
-
export * from "./utils/
|
|
36
|
-
export * from "./utils/
|
|
37
|
-
export * from "./utils/
|
|
38
|
-
export * from "./utils/
|
|
39
|
-
export * from "./utils/
|
|
40
|
-
export * from "./utils/
|
|
41
|
-
export * from "./utils/
|
|
42
|
-
export * from "./utils/
|
|
43
|
-
export * from "./utils/transferable";
|
|
44
|
-
export * from "./utils/
|
|
45
|
-
export * from "./utils/
|
|
46
|
-
export * from "./utils/
|
|
47
|
-
export * from "./utils/error";
|
|
34
|
+
//#region utils (namespace exports)
|
|
35
|
+
export * as obj from "./utils/obj";
|
|
36
|
+
export * as str from "./utils/str";
|
|
37
|
+
export * as num from "./utils/num";
|
|
38
|
+
export * as bytes from "./utils/bytes";
|
|
39
|
+
export * as path from "./utils/path";
|
|
40
|
+
export * as json from "./utils/json";
|
|
41
|
+
export * as xml from "./utils/xml";
|
|
42
|
+
export * as wait from "./utils/wait";
|
|
43
|
+
export * as transfer from "./utils/transferable";
|
|
44
|
+
export * as err from "./utils/error";
|
|
45
|
+
export * as dt from "./utils/date-format";
|
|
46
|
+
export * as primitive from "./utils/primitive";
|
|
48
47
|
//#endregion
|
|
49
48
|
|
|
50
|
-
//#region
|
|
51
|
-
export * from "./
|
|
49
|
+
//#region utils (direct exports)
|
|
50
|
+
export * from "./utils/template-strings";
|
|
51
|
+
export * from "./utils/zip";
|
|
52
52
|
//#endregion
|
|
53
53
|
|
|
54
54
|
//#region type utilities
|
package/src/types/date-only.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArgumentError } from "../errors/argument-error";
|
|
2
|
-
import {
|
|
2
|
+
import { format, normalizeMonth } from "../utils/date-format";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Date class (without time: yyyy-MM-dd, immutable)
|
|
@@ -327,7 +327,7 @@ export class DateOnly {
|
|
|
327
327
|
* @see dtFormat for supported format strings
|
|
328
328
|
*/
|
|
329
329
|
toFormatString(formatStr: string): string {
|
|
330
|
-
return
|
|
330
|
+
return format(formatStr, {
|
|
331
331
|
year: this.year,
|
|
332
332
|
month: this.month,
|
|
333
333
|
day: this.day,
|
package/src/types/date-time.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArgumentError } from "../errors/argument-error";
|
|
2
|
-
import { convert12To24,
|
|
2
|
+
import { convert12To24, format, normalizeMonth } from "../utils/date-format";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* DateTime class (immutable)
|
|
@@ -355,7 +355,7 @@ export class DateTime {
|
|
|
355
355
|
* @see dtFormat for supported format strings
|
|
356
356
|
*/
|
|
357
357
|
toFormatString(formatStr: string): string {
|
|
358
|
-
return
|
|
358
|
+
return format(formatStr, {
|
|
359
359
|
year: this.year,
|
|
360
360
|
month: this.month,
|
|
361
361
|
day: this.day,
|