ts-data-forge 6.8.0 → 6.9.0
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/dist/array/impl/array-utils-set-op.d.mts.map +1 -1
- package/dist/array/impl/array-utils-set-op.mjs +1 -3
- package/dist/array/impl/array-utils-set-op.mjs.map +1 -1
- package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-validation.mjs +2 -6
- package/dist/array/impl/array-utils-validation.mjs.map +1 -1
- package/dist/object/object.d.mts +52 -0
- package/dist/object/object.d.mts.map +1 -1
- package/dist/object/object.mjs +103 -1
- package/dist/object/object.mjs.map +1 -1
- package/dist/others/fast-deep-equal.d.mts.map +1 -1
- package/dist/others/fast-deep-equal.mjs +0 -1
- package/dist/others/fast-deep-equal.mjs.map +1 -1
- package/package.json +12 -12
- package/src/array/impl/array-utils-overload-type-error.test.mts +2 -4
- package/src/array/impl/array-utils-set-op.mts +0 -1
- package/src/array/impl/array-utils-validation.mts +2 -6
- package/src/functional/optional.test.mts +5 -7
- package/src/functional/result.test.mts +8 -10
- package/src/functional/ternary-result.test.mts +4 -4
- package/src/json/json.test.mts +5 -5
- package/src/number/branded-types/finite-number.test.mts +11 -15
- package/src/number/branded-types/int.test.mts +13 -13
- package/src/number/branded-types/int16.test.mts +15 -15
- package/src/number/branded-types/int32.test.mts +15 -15
- package/src/number/branded-types/non-negative-finite-number.test.mts +15 -19
- package/src/number/branded-types/non-negative-int16.test.mts +15 -15
- package/src/number/branded-types/non-negative-int32.test.mts +15 -15
- package/src/number/branded-types/non-zero-finite-number.test.mts +18 -18
- package/src/number/branded-types/non-zero-int.test.mts +14 -18
- package/src/number/branded-types/non-zero-int16.test.mts +15 -19
- package/src/number/branded-types/non-zero-int32.test.mts +15 -19
- package/src/number/branded-types/non-zero-safe-int.test.mts +18 -22
- package/src/number/branded-types/non-zero-uint16.test.mts +15 -15
- package/src/number/branded-types/non-zero-uint32.test.mts +15 -15
- package/src/number/branded-types/positive-finite-number.test.mts +18 -18
- package/src/number/branded-types/positive-int.test.mts +16 -22
- package/src/number/branded-types/positive-int16.test.mts +14 -14
- package/src/number/branded-types/positive-int32.test.mts +14 -14
- package/src/number/branded-types/positive-safe-int.test.mts +18 -20
- package/src/number/branded-types/positive-uint16.test.mts +15 -15
- package/src/number/branded-types/positive-uint32.test.mts +15 -15
- package/src/number/branded-types/safe-int.test.mts +17 -21
- package/src/number/branded-types/safe-uint.test.mts +16 -22
- package/src/number/branded-types/uint.test.mts +14 -14
- package/src/number/branded-types/uint16.test.mts +14 -14
- package/src/number/branded-types/uint32.test.mts +14 -14
- package/src/number/enum/int8.test.mts +1 -1
- package/src/number/enum/uint8.test.mts +1 -1
- package/src/object/object.mts +170 -1
- package/src/object/object.test.mts +172 -0
- package/src/others/fast-deep-equal.mts +0 -1
- package/src/others/unknown-to-string.test.mts +1 -1
|
@@ -9,45 +9,45 @@ import {
|
|
|
9
9
|
describe('PositiveUint16 test', () => {
|
|
10
10
|
describe(asPositiveUint16, () => {
|
|
11
11
|
test('accepts valid positive uint16 values', () => {
|
|
12
|
-
expect(() => asPositiveUint16(1)).not.
|
|
12
|
+
expect(() => asPositiveUint16(1)).not.toThrow();
|
|
13
13
|
|
|
14
|
-
expect(() => asPositiveUint16(1000)).not.
|
|
14
|
+
expect(() => asPositiveUint16(1000)).not.toThrow();
|
|
15
15
|
|
|
16
|
-
expect(() => asPositiveUint16(65_535)).not.
|
|
16
|
+
expect(() => asPositiveUint16(65_535)).not.toThrow(); // 2^16 - 1
|
|
17
17
|
|
|
18
|
-
expect(() => asPositiveUint16(32_768)).not.
|
|
18
|
+
expect(() => asPositiveUint16(32_768)).not.toThrow(); // 2^15
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
test('rejects zero', () => {
|
|
22
|
-
expect(() => asPositiveUint16(0)).
|
|
22
|
+
expect(() => asPositiveUint16(0)).toThrow(TypeError);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test('rejects values outside uint16 range', () => {
|
|
26
|
-
expect(() => asPositiveUint16(65_536)).
|
|
26
|
+
expect(() => asPositiveUint16(65_536)).toThrow(TypeError); // 2^16
|
|
27
27
|
|
|
28
|
-
expect(() => asPositiveUint16(100_000)).
|
|
28
|
+
expect(() => asPositiveUint16(100_000)).toThrow(TypeError);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
test('rejects negative integers', () => {
|
|
32
|
-
expect(() => asPositiveUint16(-1)).
|
|
32
|
+
expect(() => asPositiveUint16(-1)).toThrow(TypeError);
|
|
33
33
|
|
|
34
|
-
expect(() => asPositiveUint16(-42)).
|
|
34
|
+
expect(() => asPositiveUint16(-42)).toThrow(TypeError);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
test('rejects non-integers', () => {
|
|
38
|
-
expect(() => asPositiveUint16(Number.NaN)).
|
|
38
|
+
expect(() => asPositiveUint16(Number.NaN)).toThrow(TypeError);
|
|
39
39
|
|
|
40
|
-
expect(() => asPositiveUint16(Number.POSITIVE_INFINITY)).
|
|
40
|
+
expect(() => asPositiveUint16(Number.POSITIVE_INFINITY)).toThrow(
|
|
41
41
|
TypeError,
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
expect(() => asPositiveUint16(Number.NEGATIVE_INFINITY)).
|
|
44
|
+
expect(() => asPositiveUint16(Number.NEGATIVE_INFINITY)).toThrow(
|
|
45
45
|
TypeError,
|
|
46
46
|
);
|
|
47
47
|
|
|
48
|
-
expect(() => asPositiveUint16(1.2)).
|
|
48
|
+
expect(() => asPositiveUint16(1.2)).toThrow(TypeError);
|
|
49
49
|
|
|
50
|
-
expect(() => asPositiveUint16(-3.4)).
|
|
50
|
+
expect(() => asPositiveUint16(-3.4)).toThrow(TypeError);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
test('returns the same value for valid inputs', () => {
|
|
@@ -70,7 +70,7 @@ describe('PositiveUint16 test', () => {
|
|
|
70
70
|
] as const)(
|
|
71
71
|
`asPositiveUint16($name) should throw a TypeError`,
|
|
72
72
|
({ value }) => {
|
|
73
|
-
expect(() => asPositiveUint16(value)).
|
|
73
|
+
expect(() => asPositiveUint16(value)).toThrow(
|
|
74
74
|
new TypeError(
|
|
75
75
|
`Expected a positive integer in [1, 2^16), got: ${value}`,
|
|
76
76
|
),
|
|
@@ -9,45 +9,45 @@ import {
|
|
|
9
9
|
describe('PositiveUint32 test', () => {
|
|
10
10
|
describe(asPositiveUint32, () => {
|
|
11
11
|
test('accepts valid positive uint32 values', () => {
|
|
12
|
-
expect(() => asPositiveUint32(1)).not.
|
|
12
|
+
expect(() => asPositiveUint32(1)).not.toThrow();
|
|
13
13
|
|
|
14
|
-
expect(() => asPositiveUint32(1000)).not.
|
|
14
|
+
expect(() => asPositiveUint32(1000)).not.toThrow();
|
|
15
15
|
|
|
16
|
-
expect(() => asPositiveUint32(4_294_967_295)).not.
|
|
16
|
+
expect(() => asPositiveUint32(4_294_967_295)).not.toThrow(); // 2^32 - 1
|
|
17
17
|
|
|
18
|
-
expect(() => asPositiveUint32(2_147_483_648)).not.
|
|
18
|
+
expect(() => asPositiveUint32(2_147_483_648)).not.toThrow(); // 2^31
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
test('rejects zero', () => {
|
|
22
|
-
expect(() => asPositiveUint32(0)).
|
|
22
|
+
expect(() => asPositiveUint32(0)).toThrow(TypeError);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test('rejects values outside uint32 range', () => {
|
|
26
|
-
expect(() => asPositiveUint32(4_294_967_296)).
|
|
26
|
+
expect(() => asPositiveUint32(4_294_967_296)).toThrow(TypeError); // 2^32
|
|
27
27
|
|
|
28
|
-
expect(() => asPositiveUint32(10_000_000_000)).
|
|
28
|
+
expect(() => asPositiveUint32(10_000_000_000)).toThrow(TypeError);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
test('rejects negative integers', () => {
|
|
32
|
-
expect(() => asPositiveUint32(-1)).
|
|
32
|
+
expect(() => asPositiveUint32(-1)).toThrow(TypeError);
|
|
33
33
|
|
|
34
|
-
expect(() => asPositiveUint32(-42)).
|
|
34
|
+
expect(() => asPositiveUint32(-42)).toThrow(TypeError);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
test('rejects non-integers', () => {
|
|
38
|
-
expect(() => asPositiveUint32(Number.NaN)).
|
|
38
|
+
expect(() => asPositiveUint32(Number.NaN)).toThrow(TypeError);
|
|
39
39
|
|
|
40
|
-
expect(() => asPositiveUint32(Number.POSITIVE_INFINITY)).
|
|
40
|
+
expect(() => asPositiveUint32(Number.POSITIVE_INFINITY)).toThrow(
|
|
41
41
|
TypeError,
|
|
42
42
|
);
|
|
43
43
|
|
|
44
|
-
expect(() => asPositiveUint32(Number.NEGATIVE_INFINITY)).
|
|
44
|
+
expect(() => asPositiveUint32(Number.NEGATIVE_INFINITY)).toThrow(
|
|
45
45
|
TypeError,
|
|
46
46
|
);
|
|
47
47
|
|
|
48
|
-
expect(() => asPositiveUint32(1.2)).
|
|
48
|
+
expect(() => asPositiveUint32(1.2)).toThrow(TypeError);
|
|
49
49
|
|
|
50
|
-
expect(() => asPositiveUint32(-3.4)).
|
|
50
|
+
expect(() => asPositiveUint32(-3.4)).toThrow(TypeError);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
test('returns the same value for valid inputs', () => {
|
|
@@ -70,7 +70,7 @@ describe('PositiveUint32 test', () => {
|
|
|
70
70
|
] as const)(
|
|
71
71
|
`asPositiveUint32($name) should throw a TypeError`,
|
|
72
72
|
({ value }) => {
|
|
73
|
-
expect(() => asPositiveUint32(value)).
|
|
73
|
+
expect(() => asPositiveUint32(value)).toThrow(
|
|
74
74
|
new TypeError(
|
|
75
75
|
`Expected a positive integer in [1, 2^32), got: ${value}`,
|
|
76
76
|
),
|
|
@@ -5,45 +5,41 @@ import { asSafeInt, SafeInt } from './safe-int.mjs';
|
|
|
5
5
|
describe('SafeInt test', () => {
|
|
6
6
|
describe(asSafeInt, () => {
|
|
7
7
|
test('accepts valid safe integers', () => {
|
|
8
|
-
expect(() => asSafeInt(0)).not.
|
|
8
|
+
expect(() => asSafeInt(0)).not.toThrow();
|
|
9
9
|
|
|
10
|
-
expect(() => asSafeInt(1)).not.
|
|
10
|
+
expect(() => asSafeInt(1)).not.toThrow();
|
|
11
11
|
|
|
12
|
-
expect(() => asSafeInt(-1)).not.
|
|
12
|
+
expect(() => asSafeInt(-1)).not.toThrow();
|
|
13
13
|
|
|
14
|
-
expect(() => asSafeInt(42)).not.
|
|
14
|
+
expect(() => asSafeInt(42)).not.toThrow();
|
|
15
15
|
|
|
16
|
-
expect(() => asSafeInt(-42)).not.
|
|
16
|
+
expect(() => asSafeInt(-42)).not.toThrow();
|
|
17
17
|
|
|
18
|
-
expect(() => asSafeInt(Number.MAX_SAFE_INTEGER)).not.
|
|
18
|
+
expect(() => asSafeInt(Number.MAX_SAFE_INTEGER)).not.toThrow();
|
|
19
19
|
|
|
20
|
-
expect(() => asSafeInt(Number.MIN_SAFE_INTEGER)).not.
|
|
20
|
+
expect(() => asSafeInt(Number.MIN_SAFE_INTEGER)).not.toThrow();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
test('rejects values outside safe integer range', () => {
|
|
24
|
-
expect(() => asSafeInt(Number.MAX_SAFE_INTEGER + 1)).
|
|
25
|
-
TypeError,
|
|
26
|
-
);
|
|
24
|
+
expect(() => asSafeInt(Number.MAX_SAFE_INTEGER + 1)).toThrow(TypeError);
|
|
27
25
|
|
|
28
|
-
expect(() => asSafeInt(Number.MIN_SAFE_INTEGER - 1)).
|
|
29
|
-
TypeError,
|
|
30
|
-
);
|
|
26
|
+
expect(() => asSafeInt(Number.MIN_SAFE_INTEGER - 1)).toThrow(TypeError);
|
|
31
27
|
|
|
32
|
-
expect(() => asSafeInt(Number.MAX_VALUE)).
|
|
28
|
+
expect(() => asSafeInt(Number.MAX_VALUE)).toThrow(TypeError);
|
|
33
29
|
|
|
34
|
-
expect(() => asSafeInt(-Number.MAX_VALUE)).
|
|
30
|
+
expect(() => asSafeInt(-Number.MAX_VALUE)).toThrow(TypeError);
|
|
35
31
|
});
|
|
36
32
|
|
|
37
33
|
test('rejects non-integers', () => {
|
|
38
|
-
expect(() => asSafeInt(Number.NaN)).
|
|
34
|
+
expect(() => asSafeInt(Number.NaN)).toThrow(TypeError);
|
|
39
35
|
|
|
40
|
-
expect(() => asSafeInt(Number.POSITIVE_INFINITY)).
|
|
36
|
+
expect(() => asSafeInt(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
41
37
|
|
|
42
|
-
expect(() => asSafeInt(Number.NEGATIVE_INFINITY)).
|
|
38
|
+
expect(() => asSafeInt(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
43
39
|
|
|
44
|
-
expect(() => asSafeInt(1.2)).
|
|
40
|
+
expect(() => asSafeInt(1.2)).toThrow(TypeError);
|
|
45
41
|
|
|
46
|
-
expect(() => asSafeInt(-3.4)).
|
|
42
|
+
expect(() => asSafeInt(-3.4)).toThrow(TypeError);
|
|
47
43
|
});
|
|
48
44
|
|
|
49
45
|
test('returns the same value for valid inputs', () => {
|
|
@@ -65,7 +61,7 @@ describe('SafeInt test', () => {
|
|
|
65
61
|
{ name: '1.2', value: 1.2 },
|
|
66
62
|
{ name: '-3.4', value: -3.4 },
|
|
67
63
|
] as const)(`asSafeInt($name) should throw a TypeError`, ({ value }) => {
|
|
68
|
-
expect(() => asSafeInt(value)).
|
|
64
|
+
expect(() => asSafeInt(value)).toThrow(
|
|
69
65
|
new TypeError(`Expected a safe integer, got: ${value}`),
|
|
70
66
|
);
|
|
71
67
|
});
|
|
@@ -5,47 +5,41 @@ import { asSafeUint, isSafeUint, SafeUint } from './safe-uint.mjs';
|
|
|
5
5
|
describe('SafeUint test', () => {
|
|
6
6
|
describe(asSafeUint, () => {
|
|
7
7
|
test('accepts valid safe unsigned integers', () => {
|
|
8
|
-
expect(() => asSafeUint(0)).not.
|
|
8
|
+
expect(() => asSafeUint(0)).not.toThrow();
|
|
9
9
|
|
|
10
|
-
expect(() => asSafeUint(1)).not.
|
|
10
|
+
expect(() => asSafeUint(1)).not.toThrow();
|
|
11
11
|
|
|
12
|
-
expect(() => asSafeUint(42)).not.
|
|
12
|
+
expect(() => asSafeUint(42)).not.toThrow();
|
|
13
13
|
|
|
14
|
-
expect(() => asSafeUint(100)).not.
|
|
14
|
+
expect(() => asSafeUint(100)).not.toThrow();
|
|
15
15
|
|
|
16
|
-
expect(() => asSafeUint(Number.MAX_SAFE_INTEGER)).not.
|
|
16
|
+
expect(() => asSafeUint(Number.MAX_SAFE_INTEGER)).not.toThrow();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
test('rejects negative numbers', () => {
|
|
20
|
-
expect(() => asSafeUint(-1)).
|
|
20
|
+
expect(() => asSafeUint(-1)).toThrow(TypeError);
|
|
21
21
|
|
|
22
|
-
expect(() => asSafeUint(-42)).
|
|
22
|
+
expect(() => asSafeUint(-42)).toThrow(TypeError);
|
|
23
23
|
|
|
24
|
-
expect(() => asSafeUint(Number.MIN_SAFE_INTEGER)).
|
|
24
|
+
expect(() => asSafeUint(Number.MIN_SAFE_INTEGER)).toThrow(TypeError);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
test('rejects values outside safe integer range', () => {
|
|
28
|
-
expect(() => asSafeUint(Number.MAX_SAFE_INTEGER + 1)).
|
|
29
|
-
TypeError,
|
|
30
|
-
);
|
|
28
|
+
expect(() => asSafeUint(Number.MAX_SAFE_INTEGER + 1)).toThrow(TypeError);
|
|
31
29
|
|
|
32
|
-
expect(() => asSafeUint(Number.MAX_VALUE)).
|
|
30
|
+
expect(() => asSafeUint(Number.MAX_VALUE)).toThrow(TypeError);
|
|
33
31
|
});
|
|
34
32
|
|
|
35
33
|
test('rejects non-integers', () => {
|
|
36
|
-
expect(() => asSafeUint(Number.NaN)).
|
|
34
|
+
expect(() => asSafeUint(Number.NaN)).toThrow(TypeError);
|
|
37
35
|
|
|
38
|
-
expect(() => asSafeUint(Number.POSITIVE_INFINITY)).
|
|
39
|
-
TypeError,
|
|
40
|
-
);
|
|
36
|
+
expect(() => asSafeUint(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
41
37
|
|
|
42
|
-
expect(() => asSafeUint(Number.NEGATIVE_INFINITY)).
|
|
43
|
-
TypeError,
|
|
44
|
-
);
|
|
38
|
+
expect(() => asSafeUint(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
45
39
|
|
|
46
|
-
expect(() => asSafeUint(1.2)).
|
|
40
|
+
expect(() => asSafeUint(1.2)).toThrow(TypeError);
|
|
47
41
|
|
|
48
|
-
expect(() => asSafeUint(-3.4)).
|
|
42
|
+
expect(() => asSafeUint(-3.4)).toThrow(TypeError);
|
|
49
43
|
});
|
|
50
44
|
|
|
51
45
|
test('returns the same value for valid inputs', () => {
|
|
@@ -66,7 +60,7 @@ describe('SafeUint test', () => {
|
|
|
66
60
|
{ name: '-3.4', value: -3.4 },
|
|
67
61
|
{ name: '-1', value: -1 },
|
|
68
62
|
] as const)(`asSafeUint($name) should throw a TypeError`, ({ value }) => {
|
|
69
|
-
expect(() => asSafeUint(value)).
|
|
63
|
+
expect(() => asSafeUint(value)).toThrow(
|
|
70
64
|
new TypeError(`Expected a non-negative safe integer, got: ${value}`),
|
|
71
65
|
);
|
|
72
66
|
});
|
|
@@ -5,35 +5,35 @@ import { asUint, isUint, Uint } from './uint.mjs';
|
|
|
5
5
|
describe('Uint test', () => {
|
|
6
6
|
describe(asUint, () => {
|
|
7
7
|
test('accepts valid unsigned integers', () => {
|
|
8
|
-
expect(() => asUint(0)).not.
|
|
8
|
+
expect(() => asUint(0)).not.toThrow();
|
|
9
9
|
|
|
10
|
-
expect(() => asUint(1)).not.
|
|
10
|
+
expect(() => asUint(1)).not.toThrow();
|
|
11
11
|
|
|
12
|
-
expect(() => asUint(42)).not.
|
|
12
|
+
expect(() => asUint(42)).not.toThrow();
|
|
13
13
|
|
|
14
|
-
expect(() => asUint(100)).not.
|
|
14
|
+
expect(() => asUint(100)).not.toThrow();
|
|
15
15
|
|
|
16
|
-
expect(() => asUint(Number.MAX_SAFE_INTEGER)).not.
|
|
16
|
+
expect(() => asUint(Number.MAX_SAFE_INTEGER)).not.toThrow();
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
test('rejects negative integers', () => {
|
|
20
|
-
expect(() => asUint(-1)).
|
|
20
|
+
expect(() => asUint(-1)).toThrow(TypeError);
|
|
21
21
|
|
|
22
|
-
expect(() => asUint(-42)).
|
|
22
|
+
expect(() => asUint(-42)).toThrow(TypeError);
|
|
23
23
|
|
|
24
|
-
expect(() => asUint(Number.MIN_SAFE_INTEGER)).
|
|
24
|
+
expect(() => asUint(Number.MIN_SAFE_INTEGER)).toThrow(TypeError);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
test('rejects non-integers', () => {
|
|
28
|
-
expect(() => asUint(Number.NaN)).
|
|
28
|
+
expect(() => asUint(Number.NaN)).toThrow(TypeError);
|
|
29
29
|
|
|
30
|
-
expect(() => asUint(Number.POSITIVE_INFINITY)).
|
|
30
|
+
expect(() => asUint(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
31
31
|
|
|
32
|
-
expect(() => asUint(Number.NEGATIVE_INFINITY)).
|
|
32
|
+
expect(() => asUint(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
33
33
|
|
|
34
|
-
expect(() => asUint(1.2)).
|
|
34
|
+
expect(() => asUint(1.2)).toThrow(TypeError);
|
|
35
35
|
|
|
36
|
-
expect(() => asUint(-3.4)).
|
|
36
|
+
expect(() => asUint(-3.4)).toThrow(TypeError);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
test('returns the same value for valid inputs', () => {
|
|
@@ -52,7 +52,7 @@ describe('Uint test', () => {
|
|
|
52
52
|
{ name: '-3.4', value: -3.4 },
|
|
53
53
|
{ name: '-1', value: -1 },
|
|
54
54
|
] as const)(`asUint($name) should throw a TypeError`, ({ value }) => {
|
|
55
|
-
expect(() => asUint(value)).
|
|
55
|
+
expect(() => asUint(value)).toThrow(
|
|
56
56
|
new TypeError(`Expected a non-negative integer, got: ${value}`),
|
|
57
57
|
);
|
|
58
58
|
});
|
|
@@ -6,37 +6,37 @@ import { asUint16, isUint16, Uint16 } from './uint16.mjs';
|
|
|
6
6
|
describe('Uint16 test', () => {
|
|
7
7
|
describe(asUint16, () => {
|
|
8
8
|
test('accepts valid uint16 values', () => {
|
|
9
|
-
expect(() => asUint16(0)).not.
|
|
9
|
+
expect(() => asUint16(0)).not.toThrow();
|
|
10
10
|
|
|
11
|
-
expect(() => asUint16(1)).not.
|
|
11
|
+
expect(() => asUint16(1)).not.toThrow();
|
|
12
12
|
|
|
13
|
-
expect(() => asUint16(65_535)).not.
|
|
13
|
+
expect(() => asUint16(65_535)).not.toThrow(); // 2^16 - 1
|
|
14
14
|
|
|
15
|
-
expect(() => asUint16(32_768)).not.
|
|
15
|
+
expect(() => asUint16(32_768)).not.toThrow(); // 2^15
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
test('rejects values outside uint16 range', () => {
|
|
19
|
-
expect(() => asUint16(65_536)).
|
|
19
|
+
expect(() => asUint16(65_536)).toThrow(TypeError); // 2^16
|
|
20
20
|
|
|
21
|
-
expect(() => asUint16(100_000)).
|
|
21
|
+
expect(() => asUint16(100_000)).toThrow(TypeError);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
test('rejects negative integers', () => {
|
|
25
|
-
expect(() => asUint16(-1)).
|
|
25
|
+
expect(() => asUint16(-1)).toThrow(TypeError);
|
|
26
26
|
|
|
27
|
-
expect(() => asUint16(-42)).
|
|
27
|
+
expect(() => asUint16(-42)).toThrow(TypeError);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test('rejects non-integers', () => {
|
|
31
|
-
expect(() => asUint16(Number.NaN)).
|
|
31
|
+
expect(() => asUint16(Number.NaN)).toThrow(TypeError);
|
|
32
32
|
|
|
33
|
-
expect(() => asUint16(Number.POSITIVE_INFINITY)).
|
|
33
|
+
expect(() => asUint16(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
34
34
|
|
|
35
|
-
expect(() => asUint16(Number.NEGATIVE_INFINITY)).
|
|
35
|
+
expect(() => asUint16(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
36
36
|
|
|
37
|
-
expect(() => asUint16(1.2)).
|
|
37
|
+
expect(() => asUint16(1.2)).toThrow(TypeError);
|
|
38
38
|
|
|
39
|
-
expect(() => asUint16(-3.4)).
|
|
39
|
+
expect(() => asUint16(-3.4)).toThrow(TypeError);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
test('returns the same value for valid inputs', () => {
|
|
@@ -55,7 +55,7 @@ describe('Uint16 test', () => {
|
|
|
55
55
|
{ name: '-3.4', value: -3.4 },
|
|
56
56
|
{ name: '-1', value: -1 },
|
|
57
57
|
] as const)(`asUint16($name) should throw a TypeError`, ({ value }) => {
|
|
58
|
-
expect(() => asUint16(value)).
|
|
58
|
+
expect(() => asUint16(value)).toThrow(
|
|
59
59
|
new TypeError(
|
|
60
60
|
`Expected a non-negative integer less than 2^16, got: ${value}`,
|
|
61
61
|
),
|
|
@@ -6,37 +6,37 @@ import { asUint32, isUint32, Uint32 } from './uint32.mjs';
|
|
|
6
6
|
describe('Uint32 test', () => {
|
|
7
7
|
describe(asUint32, () => {
|
|
8
8
|
test('accepts valid uint32 values', () => {
|
|
9
|
-
expect(() => asUint32(0)).not.
|
|
9
|
+
expect(() => asUint32(0)).not.toThrow();
|
|
10
10
|
|
|
11
|
-
expect(() => asUint32(1)).not.
|
|
11
|
+
expect(() => asUint32(1)).not.toThrow();
|
|
12
12
|
|
|
13
|
-
expect(() => asUint32(4_294_967_295)).not.
|
|
13
|
+
expect(() => asUint32(4_294_967_295)).not.toThrow(); // 2^32 - 1
|
|
14
14
|
|
|
15
|
-
expect(() => asUint32(2_147_483_648)).not.
|
|
15
|
+
expect(() => asUint32(2_147_483_648)).not.toThrow(); // 2^31
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
test('rejects values outside uint32 range', () => {
|
|
19
|
-
expect(() => asUint32(4_294_967_296)).
|
|
19
|
+
expect(() => asUint32(4_294_967_296)).toThrow(TypeError); // 2^32
|
|
20
20
|
|
|
21
|
-
expect(() => asUint32(10_000_000_000)).
|
|
21
|
+
expect(() => asUint32(10_000_000_000)).toThrow(TypeError);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
test('rejects negative integers', () => {
|
|
25
|
-
expect(() => asUint32(-1)).
|
|
25
|
+
expect(() => asUint32(-1)).toThrow(TypeError);
|
|
26
26
|
|
|
27
|
-
expect(() => asUint32(-42)).
|
|
27
|
+
expect(() => asUint32(-42)).toThrow(TypeError);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test('rejects non-integers', () => {
|
|
31
|
-
expect(() => asUint32(Number.NaN)).
|
|
31
|
+
expect(() => asUint32(Number.NaN)).toThrow(TypeError);
|
|
32
32
|
|
|
33
|
-
expect(() => asUint32(Number.POSITIVE_INFINITY)).
|
|
33
|
+
expect(() => asUint32(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
34
34
|
|
|
35
|
-
expect(() => asUint32(Number.NEGATIVE_INFINITY)).
|
|
35
|
+
expect(() => asUint32(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
36
36
|
|
|
37
|
-
expect(() => asUint32(1.2)).
|
|
37
|
+
expect(() => asUint32(1.2)).toThrow(TypeError);
|
|
38
38
|
|
|
39
|
-
expect(() => asUint32(-3.4)).
|
|
39
|
+
expect(() => asUint32(-3.4)).toThrow(TypeError);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
test('returns the same value for valid inputs', () => {
|
|
@@ -55,7 +55,7 @@ describe('Uint32 test', () => {
|
|
|
55
55
|
{ name: '-3.4', value: -3.4 },
|
|
56
56
|
{ name: '-1', value: -1 },
|
|
57
57
|
] as const)(`asUint32($name) should throw a TypeError`, ({ value }) => {
|
|
58
|
-
expect(() => asUint32(value)).
|
|
58
|
+
expect(() => asUint32(value)).toThrow(
|
|
59
59
|
new TypeError(
|
|
60
60
|
`Expected a non-negative integer less than 2^32, got: ${value}`,
|
|
61
61
|
),
|
|
@@ -35,7 +35,7 @@ describe('Int8 test', () => {
|
|
|
35
35
|
{ value: Number.POSITIVE_INFINITY, name: 'Infinity' },
|
|
36
36
|
{ value: Number.NEGATIVE_INFINITY, name: '-Infinity' },
|
|
37
37
|
])('asInt8($name) should throw TypeError', ({ value }) => {
|
|
38
|
-
expect(() => asInt8(value)).
|
|
38
|
+
expect(() => asInt8(value)).toThrow(TypeError);
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -35,7 +35,7 @@ describe('Uint8 test', () => {
|
|
|
35
35
|
{ value: Number.POSITIVE_INFINITY, name: 'Infinity' },
|
|
36
36
|
{ value: Number.NEGATIVE_INFINITY, name: '-Infinity' },
|
|
37
37
|
])('asUint8($name) should throw TypeError', ({ value }) => {
|
|
38
|
-
expect(() => asUint8(value)).
|
|
38
|
+
expect(() => asUint8(value)).toThrow(TypeError);
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
|
package/src/object/object.mts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { Arr } from '../array/index.mjs';
|
|
2
|
+
import { hasKey, isRecord } from '../guard/index.mjs';
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* A collection of type-safe object utility functions providing functional
|
|
3
6
|
* programming patterns for object manipulation, including pick, omit, shallow
|
|
@@ -58,7 +61,6 @@ export namespace Obj {
|
|
|
58
61
|
|
|
59
62
|
const bEntries = Object.entries(b);
|
|
60
63
|
|
|
61
|
-
// eslint-disable-next-line ts-data-forge/prefer-arr-is-array-of-length
|
|
62
64
|
if (aEntries.length !== bEntries.length) return false;
|
|
63
65
|
|
|
64
66
|
return aEntries.every(([k, v]) => eq(b[k], v));
|
|
@@ -332,8 +334,175 @@ export namespace Obj {
|
|
|
332
334
|
): TsDataForgeInternals.MergeAll<Records> =>
|
|
333
335
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
334
336
|
Object.fromEntries(records.flatMap((r) => Object.entries(r))) as never;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Deeply picks a nested property from an object along the specified key path.
|
|
340
|
+
* Supports both direct and curried usage.
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
*
|
|
344
|
+
* ```ts
|
|
345
|
+
* const data = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 } as const;
|
|
346
|
+
*
|
|
347
|
+
* // Direct usage
|
|
348
|
+
* const result = Obj.deepPick(data, ['a', 'b', 'c']);
|
|
349
|
+
* assert.deepStrictEqual(result, { a: { b: { c: 1 } } });
|
|
350
|
+
*
|
|
351
|
+
* // Curried usage with pipe
|
|
352
|
+
* const pickName = Obj.deepPick(['user', 'name']);
|
|
353
|
+
* const result2 = pipe(data).map(pickName).value;
|
|
354
|
+
* ```
|
|
355
|
+
*
|
|
356
|
+
* @template R - The type of the input record
|
|
357
|
+
* @template Path - The key path tuple
|
|
358
|
+
* @param record - The source record
|
|
359
|
+
* @param path - A readonly tuple of keys representing the nested path
|
|
360
|
+
* @returns A new record containing only the nested property at the path
|
|
361
|
+
*/
|
|
362
|
+
export function deepPick<
|
|
363
|
+
const R extends UnknownRecord,
|
|
364
|
+
const Path extends readonly (string | number)[],
|
|
365
|
+
>(record: R, path: Path): DeepPick<R, Path>;
|
|
366
|
+
|
|
367
|
+
// Curried version
|
|
368
|
+
export function deepPick<const Path extends readonly (string | number)[]>(
|
|
369
|
+
path: Path,
|
|
370
|
+
): <const R extends UnknownRecord>(record: R) => DeepPick<R, Path>;
|
|
371
|
+
|
|
372
|
+
export function deepPick<
|
|
373
|
+
const R extends UnknownRecord,
|
|
374
|
+
const Path extends readonly (string | number)[],
|
|
375
|
+
>(
|
|
376
|
+
...args: readonly [record: R, path: Path] | readonly [path: Path]
|
|
377
|
+
): DeepPick<R, Path> | ((record: R) => DeepPick<R, Path>) {
|
|
378
|
+
switch (args.length) {
|
|
379
|
+
case 2: {
|
|
380
|
+
const [record, path] = args;
|
|
381
|
+
|
|
382
|
+
return (
|
|
383
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
384
|
+
deepPickImpl(record, path) as never
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
case 1: {
|
|
389
|
+
const [path] = args;
|
|
390
|
+
|
|
391
|
+
return (record: R) => deepPick(record, path);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Deeply omits a nested property from an object along the specified key path.
|
|
398
|
+
* Supports both direct and curried usage.
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
*
|
|
402
|
+
* ```ts
|
|
403
|
+
* const data = { a: { b: { c: 1, d: 2 }, e: 3 }, f: 4 } as const;
|
|
404
|
+
*
|
|
405
|
+
* // Direct usage
|
|
406
|
+
* const result = Obj.deepOmit(data, ['a', 'b', 'c']);
|
|
407
|
+
* assert.deepStrictEqual(result, { a: { b: { d: 2 }, e: 3 }, f: 4 });
|
|
408
|
+
*
|
|
409
|
+
* // Curried usage with pipe
|
|
410
|
+
* const omitPassword = Obj.deepOmit(['user', 'password']);
|
|
411
|
+
* const result2 = pipe(data).map(omitPassword).value;
|
|
412
|
+
* ```
|
|
413
|
+
*
|
|
414
|
+
* @template R - The type of the input record
|
|
415
|
+
* @template Path - The key path tuple
|
|
416
|
+
* @param record - The source record
|
|
417
|
+
* @param path - A readonly tuple of keys representing the nested path to omit
|
|
418
|
+
* @returns A new record with the nested property at the path removed
|
|
419
|
+
*/
|
|
420
|
+
export function deepOmit<
|
|
421
|
+
const R extends UnknownRecord,
|
|
422
|
+
const Path extends readonly (string | number)[],
|
|
423
|
+
>(record: R, path: Path): DeepOmit<R, Path>;
|
|
424
|
+
|
|
425
|
+
// Curried version
|
|
426
|
+
export function deepOmit<const Path extends readonly (string | number)[]>(
|
|
427
|
+
path: Path,
|
|
428
|
+
): <const R extends UnknownRecord>(record: R) => DeepOmit<R, Path>;
|
|
429
|
+
|
|
430
|
+
export function deepOmit<
|
|
431
|
+
const R extends UnknownRecord,
|
|
432
|
+
const Path extends readonly (string | number)[],
|
|
433
|
+
>(
|
|
434
|
+
...args: readonly [record: R, path: Path] | readonly [path: Path]
|
|
435
|
+
): DeepOmit<R, Path> | ((record: R) => DeepOmit<R, Path>) {
|
|
436
|
+
switch (args.length) {
|
|
437
|
+
case 2: {
|
|
438
|
+
const [record, path] = args;
|
|
439
|
+
|
|
440
|
+
return (
|
|
441
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
442
|
+
deepOmitImpl(record, path) as never
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
case 1: {
|
|
447
|
+
const [path] = args;
|
|
448
|
+
|
|
449
|
+
return (record: R) => deepOmit(record, path);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
335
453
|
}
|
|
336
454
|
|
|
455
|
+
const deepPickImpl = (
|
|
456
|
+
record: UnknownRecord,
|
|
457
|
+
path: readonly (string | number)[],
|
|
458
|
+
): UnknownRecord => {
|
|
459
|
+
if (!Arr.isNonEmpty(path)) return record;
|
|
460
|
+
|
|
461
|
+
const head = path[0];
|
|
462
|
+
|
|
463
|
+
if (!hasKey(record, head)) return {};
|
|
464
|
+
|
|
465
|
+
const value = record[head];
|
|
466
|
+
|
|
467
|
+
const tail = path.slice(1);
|
|
468
|
+
|
|
469
|
+
if (!Arr.isNonEmpty(tail)) return { [head]: value };
|
|
470
|
+
|
|
471
|
+
if (!isRecord(value)) return { [head]: {} };
|
|
472
|
+
|
|
473
|
+
return {
|
|
474
|
+
[head]: deepPickImpl(value, tail),
|
|
475
|
+
};
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
const deepOmitImpl = (
|
|
479
|
+
record: UnknownRecord,
|
|
480
|
+
path: readonly (string | number)[],
|
|
481
|
+
): UnknownRecord => {
|
|
482
|
+
if (!Arr.isNonEmpty(path)) return record;
|
|
483
|
+
|
|
484
|
+
const head = path[0];
|
|
485
|
+
|
|
486
|
+
const tail = path.slice(1);
|
|
487
|
+
|
|
488
|
+
if (!hasKey(record, head)) return record;
|
|
489
|
+
|
|
490
|
+
if (!Arr.isNonEmpty(tail)) {
|
|
491
|
+
return Object.fromEntries(
|
|
492
|
+
Object.entries(record).filter(([k]) => k !== head),
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const value = record[head];
|
|
497
|
+
|
|
498
|
+
if (!isRecord(value)) return record;
|
|
499
|
+
|
|
500
|
+
return {
|
|
501
|
+
...record,
|
|
502
|
+
[head]: deepOmitImpl(value, tail),
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
|
|
337
506
|
/**
|
|
338
507
|
* @internal
|
|
339
508
|
* Internal type utilities for the Obj module.
|