ts-data-forge 1.0.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/LICENSE +201 -0
- package/README.md +534 -0
- package/package.json +101 -0
- package/src/array/array-utils-creation.test.mts +443 -0
- package/src/array/array-utils-modification.test.mts +197 -0
- package/src/array/array-utils-overload-type-error.test.mts +149 -0
- package/src/array/array-utils-reducing-value.test.mts +425 -0
- package/src/array/array-utils-search.test.mts +169 -0
- package/src/array/array-utils-set-op.test.mts +335 -0
- package/src/array/array-utils-slice-clamped.test.mts +113 -0
- package/src/array/array-utils-slicing.test.mts +316 -0
- package/src/array/array-utils-transformation.test.mts +790 -0
- package/src/array/array-utils-validation.test.mts +492 -0
- package/src/array/array-utils.mts +4000 -0
- package/src/array/array.test.mts +146 -0
- package/src/array/index.mts +2 -0
- package/src/array/tuple-utils.mts +519 -0
- package/src/array/tuple-utils.test.mts +518 -0
- package/src/collections/imap-mapped.mts +801 -0
- package/src/collections/imap-mapped.test.mts +860 -0
- package/src/collections/imap.mts +651 -0
- package/src/collections/imap.test.mts +932 -0
- package/src/collections/index.mts +6 -0
- package/src/collections/iset-mapped.mts +889 -0
- package/src/collections/iset-mapped.test.mts +1187 -0
- package/src/collections/iset.mts +682 -0
- package/src/collections/iset.test.mts +1084 -0
- package/src/collections/queue.mts +390 -0
- package/src/collections/queue.test.mts +282 -0
- package/src/collections/stack.mts +423 -0
- package/src/collections/stack.test.mts +225 -0
- package/src/expect-type.mts +206 -0
- package/src/functional/index.mts +4 -0
- package/src/functional/match.mts +300 -0
- package/src/functional/match.test.mts +177 -0
- package/src/functional/optional.mts +733 -0
- package/src/functional/optional.test.mts +619 -0
- package/src/functional/pipe.mts +212 -0
- package/src/functional/pipe.test.mts +85 -0
- package/src/functional/result.mts +1134 -0
- package/src/functional/result.test.mts +777 -0
- package/src/globals.d.mts +38 -0
- package/src/guard/has-key.mts +119 -0
- package/src/guard/has-key.test.mts +219 -0
- package/src/guard/index.mts +7 -0
- package/src/guard/is-non-empty-string.mts +108 -0
- package/src/guard/is-non-empty-string.test.mts +91 -0
- package/src/guard/is-non-null-object.mts +106 -0
- package/src/guard/is-non-null-object.test.mts +90 -0
- package/src/guard/is-primitive.mts +165 -0
- package/src/guard/is-primitive.test.mts +102 -0
- package/src/guard/is-record.mts +153 -0
- package/src/guard/is-record.test.mts +112 -0
- package/src/guard/is-type.mts +450 -0
- package/src/guard/is-type.test.mts +496 -0
- package/src/guard/key-is-in.mts +163 -0
- package/src/guard/key-is-in.test.mts +19 -0
- package/src/index.mts +10 -0
- package/src/iterator/index.mts +1 -0
- package/src/iterator/range.mts +120 -0
- package/src/iterator/range.test.mts +33 -0
- package/src/json/index.mts +1 -0
- package/src/json/json.mts +711 -0
- package/src/json/json.test.mts +628 -0
- package/src/number/branded-types/finite-number.mts +354 -0
- package/src/number/branded-types/finite-number.test.mts +135 -0
- package/src/number/branded-types/index.mts +26 -0
- package/src/number/branded-types/int.mts +278 -0
- package/src/number/branded-types/int.test.mts +140 -0
- package/src/number/branded-types/int16.mts +192 -0
- package/src/number/branded-types/int16.test.mts +170 -0
- package/src/number/branded-types/int32.mts +193 -0
- package/src/number/branded-types/int32.test.mts +170 -0
- package/src/number/branded-types/non-negative-finite-number.mts +223 -0
- package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
- package/src/number/branded-types/non-negative-int16.mts +187 -0
- package/src/number/branded-types/non-negative-int16.test.mts +201 -0
- package/src/number/branded-types/non-negative-int32.mts +187 -0
- package/src/number/branded-types/non-negative-int32.test.mts +204 -0
- package/src/number/branded-types/non-zero-finite-number.mts +229 -0
- package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
- package/src/number/branded-types/non-zero-int.mts +167 -0
- package/src/number/branded-types/non-zero-int.test.mts +177 -0
- package/src/number/branded-types/non-zero-int16.mts +196 -0
- package/src/number/branded-types/non-zero-int16.test.mts +195 -0
- package/src/number/branded-types/non-zero-int32.mts +196 -0
- package/src/number/branded-types/non-zero-int32.test.mts +197 -0
- package/src/number/branded-types/non-zero-safe-int.mts +196 -0
- package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
- package/src/number/branded-types/non-zero-uint16.mts +189 -0
- package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
- package/src/number/branded-types/non-zero-uint32.mts +189 -0
- package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
- package/src/number/branded-types/positive-finite-number.mts +241 -0
- package/src/number/branded-types/positive-finite-number.test.mts +204 -0
- package/src/number/branded-types/positive-int.mts +304 -0
- package/src/number/branded-types/positive-int.test.mts +176 -0
- package/src/number/branded-types/positive-int16.mts +188 -0
- package/src/number/branded-types/positive-int16.test.mts +197 -0
- package/src/number/branded-types/positive-int32.mts +188 -0
- package/src/number/branded-types/positive-int32.test.mts +197 -0
- package/src/number/branded-types/positive-safe-int.mts +187 -0
- package/src/number/branded-types/positive-safe-int.test.mts +210 -0
- package/src/number/branded-types/positive-uint16.mts +188 -0
- package/src/number/branded-types/positive-uint16.test.mts +203 -0
- package/src/number/branded-types/positive-uint32.mts +188 -0
- package/src/number/branded-types/positive-uint32.test.mts +203 -0
- package/src/number/branded-types/safe-int.mts +291 -0
- package/src/number/branded-types/safe-int.test.mts +170 -0
- package/src/number/branded-types/safe-uint.mts +187 -0
- package/src/number/branded-types/safe-uint.test.mts +176 -0
- package/src/number/branded-types/uint.mts +179 -0
- package/src/number/branded-types/uint.test.mts +158 -0
- package/src/number/branded-types/uint16.mts +186 -0
- package/src/number/branded-types/uint16.test.mts +170 -0
- package/src/number/branded-types/uint32.mts +218 -0
- package/src/number/branded-types/uint32.test.mts +170 -0
- package/src/number/enum/index.mts +2 -0
- package/src/number/enum/int8.mts +344 -0
- package/src/number/enum/int8.test.mts +180 -0
- package/src/number/enum/uint8.mts +293 -0
- package/src/number/enum/uint8.test.mts +164 -0
- package/src/number/index.mts +4 -0
- package/src/number/num.mts +604 -0
- package/src/number/num.test.mts +242 -0
- package/src/number/refined-number-utils.mts +566 -0
- package/src/object/index.mts +1 -0
- package/src/object/object.mts +447 -0
- package/src/object/object.test.mts +124 -0
- package/src/others/cast-mutable.mts +113 -0
- package/src/others/cast-readonly.mts +192 -0
- package/src/others/cast-readonly.test.mts +89 -0
- package/src/others/if-then.mts +98 -0
- package/src/others/if-then.test.mts +75 -0
- package/src/others/index.mts +7 -0
- package/src/others/map-nullable.mts +172 -0
- package/src/others/map-nullable.test.mts +297 -0
- package/src/others/memoize-function.mts +196 -0
- package/src/others/memoize-function.test.mts +168 -0
- package/src/others/tuple.mts +160 -0
- package/src/others/tuple.test.mts +11 -0
- package/src/others/unknown-to-string.mts +215 -0
- package/src/others/unknown-to-string.test.mts +114 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = NonZeroUint32;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'a non-zero integer in [1, 2^32)';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
MIN_VALUE,
|
|
10
|
+
MAX_VALUE,
|
|
11
|
+
min: min_,
|
|
12
|
+
max: max_,
|
|
13
|
+
pow,
|
|
14
|
+
add,
|
|
15
|
+
sub,
|
|
16
|
+
mul,
|
|
17
|
+
div,
|
|
18
|
+
randomNonZero: random,
|
|
19
|
+
is,
|
|
20
|
+
castType,
|
|
21
|
+
clamp,
|
|
22
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForInteger<
|
|
23
|
+
ElementType,
|
|
24
|
+
1,
|
|
25
|
+
number
|
|
26
|
+
>({
|
|
27
|
+
integerOrSafeInteger: 'SafeInteger',
|
|
28
|
+
nonZero: true,
|
|
29
|
+
MIN_VALUE: 1,
|
|
30
|
+
MAX_VALUE: 2 ** 32 - 1,
|
|
31
|
+
typeNameInMessage,
|
|
32
|
+
} as const);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a number is a NonZeroUint32 (32-bit non-zero unsigned integer in the range [1, 2^32)).
|
|
36
|
+
* @param value The value to check.
|
|
37
|
+
* @returns `true` if the value is a NonZeroUint32, `false` otherwise.
|
|
38
|
+
*/
|
|
39
|
+
export const isNonZeroUint32 = is;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Casts a number to a NonZeroUint32 type.
|
|
43
|
+
* @param value The value to cast.
|
|
44
|
+
* @returns The value as a NonZeroUint32 type.
|
|
45
|
+
* @throws {TypeError} If the value is not a non-zero integer in [1, 2^32).
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const x = asNonZeroUint32(1000); // NonZeroUint32
|
|
49
|
+
* const y = asNonZeroUint32(4294967295); // NonZeroUint32
|
|
50
|
+
* // asNonZeroUint32(0); // throws TypeError
|
|
51
|
+
* // asNonZeroUint32(-1); // throws TypeError
|
|
52
|
+
* // asNonZeroUint32(4294967296); // throws TypeError
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const asNonZeroUint32 = castType;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Namespace providing type-safe arithmetic operations for 32-bit non-zero unsigned integers.
|
|
59
|
+
*
|
|
60
|
+
* All operations automatically clamp results to the valid NonZeroUint32 range [1, 4294967295].
|
|
61
|
+
* This ensures that all arithmetic maintains the 32-bit non-zero unsigned integer constraint,
|
|
62
|
+
* with results below 1 clamped to MIN_VALUE and overflow results clamped to MAX_VALUE.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const a = asNonZeroUint32(4000000000);
|
|
67
|
+
* const b = asNonZeroUint32(1000000000);
|
|
68
|
+
*
|
|
69
|
+
* // Arithmetic operations with automatic clamping and non-zero constraint
|
|
70
|
+
* const sum = NonZeroUint32.add(a, b); // NonZeroUint32 (4294967295 - clamped to MAX_VALUE)
|
|
71
|
+
* const diff = NonZeroUint32.sub(a, b); // NonZeroUint32 (3000000000)
|
|
72
|
+
* const reverseDiff = NonZeroUint32.sub(b, a); // NonZeroUint32 (1 - clamped to MIN_VALUE)
|
|
73
|
+
* const product = NonZeroUint32.mul(a, b); // NonZeroUint32 (4294967295 - clamped due to overflow)
|
|
74
|
+
*
|
|
75
|
+
* // Range operations (maintaining non-zero constraint)
|
|
76
|
+
* const clamped = NonZeroUint32.clamp(-100); // NonZeroUint32 (1)
|
|
77
|
+
* const minimum = NonZeroUint32.min(a, b); // NonZeroUint32 (1000000000)
|
|
78
|
+
* const maximum = NonZeroUint32.max(a, b); // NonZeroUint32 (4000000000)
|
|
79
|
+
*
|
|
80
|
+
* // Utility operations
|
|
81
|
+
* const random = NonZeroUint32.random(); // NonZeroUint32 (random value in [1, 4294967295])
|
|
82
|
+
* const power = NonZeroUint32.pow(asNonZeroUint32(2), asNonZeroUint32(20)); // NonZeroUint32 (1048576)
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export const NonZeroUint32 = {
|
|
86
|
+
/**
|
|
87
|
+
* Type guard to check if a value is a NonZeroUint32.
|
|
88
|
+
* @param value The value to check.
|
|
89
|
+
* @returns `true` if the value is a 32-bit non-zero unsigned integer, `false` otherwise.
|
|
90
|
+
*/
|
|
91
|
+
is,
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The minimum value for a 32-bit non-zero unsigned integer.
|
|
95
|
+
* @readonly
|
|
96
|
+
*/
|
|
97
|
+
MIN_VALUE,
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The maximum value for a 32-bit non-zero unsigned integer.
|
|
101
|
+
* @readonly
|
|
102
|
+
*/
|
|
103
|
+
MAX_VALUE,
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns the smaller of two NonZeroUint32 values.
|
|
107
|
+
* @param a The first NonZeroUint32.
|
|
108
|
+
* @param b The second NonZeroUint32.
|
|
109
|
+
* @returns The minimum value as a NonZeroUint32.
|
|
110
|
+
*/
|
|
111
|
+
min: min_,
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Returns the larger of two NonZeroUint32 values.
|
|
115
|
+
* @param a The first NonZeroUint32.
|
|
116
|
+
* @param b The second NonZeroUint32.
|
|
117
|
+
* @returns The maximum value as a NonZeroUint32.
|
|
118
|
+
*/
|
|
119
|
+
max: max_,
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Clamps a number to the NonZeroUint32 range.
|
|
123
|
+
* @param value The number to clamp.
|
|
124
|
+
* @returns The value clamped to [1, 4294967295] as a NonZeroUint32.
|
|
125
|
+
*/
|
|
126
|
+
clamp,
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Generates a random NonZeroUint32 value within the valid range.
|
|
130
|
+
* @returns A random NonZeroUint32 between 1 and 4294967295.
|
|
131
|
+
*/
|
|
132
|
+
random,
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Raises a NonZeroUint32 to the power of another NonZeroUint32.
|
|
136
|
+
* @param a The base NonZeroUint32.
|
|
137
|
+
* @param b The exponent NonZeroUint32.
|
|
138
|
+
* @returns `a ** b` clamped to [1, 4294967295] as a NonZeroUint32.
|
|
139
|
+
*/
|
|
140
|
+
pow,
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Adds two NonZeroUint32 values.
|
|
144
|
+
* @param a The first NonZeroUint32.
|
|
145
|
+
* @param b The second NonZeroUint32.
|
|
146
|
+
* @returns `a + b` clamped to [1, 4294967295] as a NonZeroUint32.
|
|
147
|
+
*/
|
|
148
|
+
add,
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Subtracts one NonZeroUint32 from another.
|
|
152
|
+
* @param a The minuend NonZeroUint32.
|
|
153
|
+
* @param b The subtrahend NonZeroUint32.
|
|
154
|
+
* @returns `a - b` clamped to [1, 4294967295] as a NonZeroUint32 (minimum 1).
|
|
155
|
+
*/
|
|
156
|
+
sub,
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Multiplies two NonZeroUint32 values.
|
|
160
|
+
* @param a The first NonZeroUint32.
|
|
161
|
+
* @param b The second NonZeroUint32.
|
|
162
|
+
* @returns `a * b` clamped to [1, 4294967295] as a NonZeroUint32.
|
|
163
|
+
*/
|
|
164
|
+
mul,
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Divides one NonZeroUint32 by another using floor division.
|
|
168
|
+
* @param a The dividend NonZeroUint32.
|
|
169
|
+
* @param b The divisor NonZeroUint32.
|
|
170
|
+
* @returns `⌊a / b⌋` clamped to [1, 4294967295] as a NonZeroUint32.
|
|
171
|
+
*/
|
|
172
|
+
div,
|
|
173
|
+
} as const;
|
|
174
|
+
|
|
175
|
+
expectType<
|
|
176
|
+
keyof typeof NonZeroUint32,
|
|
177
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
178
|
+
ElementType,
|
|
179
|
+
'int' | 'positive' | 'range'
|
|
180
|
+
>
|
|
181
|
+
>('=');
|
|
182
|
+
|
|
183
|
+
expectType<
|
|
184
|
+
typeof NonZeroUint32,
|
|
185
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
186
|
+
ElementType,
|
|
187
|
+
'int' | 'positive' | 'range'
|
|
188
|
+
>
|
|
189
|
+
>('<=');
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import {
|
|
3
|
+
asNonZeroUint32,
|
|
4
|
+
isNonZeroUint32,
|
|
5
|
+
NonZeroUint32,
|
|
6
|
+
} from './non-zero-uint32.mjs';
|
|
7
|
+
|
|
8
|
+
describe('NonZeroUint32', () => {
|
|
9
|
+
describe('asNonZeroUint32', () => {
|
|
10
|
+
test('accepts valid non-zero uint32 values', () => {
|
|
11
|
+
expect(() => asNonZeroUint32(1)).not.toThrow();
|
|
12
|
+
expect(() => asNonZeroUint32(1000)).not.toThrow();
|
|
13
|
+
expect(() => asNonZeroUint32(4294967295)).not.toThrow(); // 2^32 - 1
|
|
14
|
+
expect(() => asNonZeroUint32(2147483648)).not.toThrow(); // 2^31
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('rejects zero', () => {
|
|
18
|
+
expect(() => asNonZeroUint32(0)).toThrow(TypeError);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('rejects values outside uint32 range', () => {
|
|
22
|
+
expect(() => asNonZeroUint32(4294967296)).toThrow(TypeError); // 2^32
|
|
23
|
+
expect(() => asNonZeroUint32(10000000000)).toThrow(TypeError);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('rejects negative integers', () => {
|
|
27
|
+
expect(() => asNonZeroUint32(-1)).toThrow(TypeError);
|
|
28
|
+
expect(() => asNonZeroUint32(-42)).toThrow(TypeError);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('rejects non-integers', () => {
|
|
32
|
+
expect(() => asNonZeroUint32(Number.NaN)).toThrow(TypeError);
|
|
33
|
+
expect(() => asNonZeroUint32(Number.POSITIVE_INFINITY)).toThrow(
|
|
34
|
+
TypeError,
|
|
35
|
+
);
|
|
36
|
+
expect(() => asNonZeroUint32(Number.NEGATIVE_INFINITY)).toThrow(
|
|
37
|
+
TypeError,
|
|
38
|
+
);
|
|
39
|
+
expect(() => asNonZeroUint32(1.2)).toThrow(TypeError);
|
|
40
|
+
expect(() => asNonZeroUint32(-3.4)).toThrow(TypeError);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('returns the same value for valid inputs', () => {
|
|
44
|
+
expect(asNonZeroUint32(5)).toBe(5);
|
|
45
|
+
expect(asNonZeroUint32(1)).toBe(1);
|
|
46
|
+
expect(asNonZeroUint32(4294967295)).toBe(4294967295);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test.each([
|
|
50
|
+
{ name: 'Number.NaN', value: Number.NaN },
|
|
51
|
+
{ name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
|
|
52
|
+
{ name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
|
|
53
|
+
{ name: '1.2', value: 1.2 },
|
|
54
|
+
{ name: '-3.4', value: -3.4 },
|
|
55
|
+
{ name: '0', value: 0 },
|
|
56
|
+
{ name: '-1', value: -1 },
|
|
57
|
+
{ name: '4294967296', value: 4294967296 },
|
|
58
|
+
] as const)(
|
|
59
|
+
`asNonZeroUint32($name) should throw a TypeError`,
|
|
60
|
+
({ value }) => {
|
|
61
|
+
expect(() => asNonZeroUint32(value)).toThrow(
|
|
62
|
+
new TypeError(
|
|
63
|
+
`Expected a non-zero integer in [1, 2^32), got: ${value}`,
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('isNonZeroUint32', () => {
|
|
71
|
+
test('correctly identifies non-zero uint32 values', () => {
|
|
72
|
+
expect(isNonZeroUint32(1)).toBe(true);
|
|
73
|
+
expect(isNonZeroUint32(1000)).toBe(true);
|
|
74
|
+
expect(isNonZeroUint32(4294967295)).toBe(true);
|
|
75
|
+
expect(isNonZeroUint32(2147483648)).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('correctly identifies zero', () => {
|
|
79
|
+
expect(isNonZeroUint32(0)).toBe(false);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('correctly identifies values outside uint32 range', () => {
|
|
83
|
+
expect(isNonZeroUint32(4294967296)).toBe(false);
|
|
84
|
+
expect(isNonZeroUint32(10000000000)).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('correctly identifies negative integers', () => {
|
|
88
|
+
expect(isNonZeroUint32(-1)).toBe(false);
|
|
89
|
+
expect(isNonZeroUint32(-42)).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('correctly identifies non-integers', () => {
|
|
93
|
+
expect(isNonZeroUint32(Number.NaN)).toBe(false);
|
|
94
|
+
expect(isNonZeroUint32(Number.POSITIVE_INFINITY)).toBe(false);
|
|
95
|
+
expect(isNonZeroUint32(Number.NEGATIVE_INFINITY)).toBe(false);
|
|
96
|
+
expect(isNonZeroUint32(1.2)).toBe(false);
|
|
97
|
+
expect(isNonZeroUint32(-3.4)).toBe(false);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('NonZeroUint32.is', () => {
|
|
102
|
+
test('same as isNonZeroUint32 function', () => {
|
|
103
|
+
expect(NonZeroUint32.is(5)).toBe(isNonZeroUint32(5));
|
|
104
|
+
expect(NonZeroUint32.is(0)).toBe(isNonZeroUint32(0));
|
|
105
|
+
expect(NonZeroUint32.is(-1)).toBe(isNonZeroUint32(-1));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('constants', () => {
|
|
110
|
+
test('MIN_VALUE and MAX_VALUE', () => {
|
|
111
|
+
expect(NonZeroUint32.MIN_VALUE).toBe(1);
|
|
112
|
+
expect(NonZeroUint32.MAX_VALUE).toBe(4294967295);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('mathematical operations', () => {
|
|
117
|
+
const a = asNonZeroUint32(1000000);
|
|
118
|
+
const b = asNonZeroUint32(500000);
|
|
119
|
+
|
|
120
|
+
test('min and max', () => {
|
|
121
|
+
expect(NonZeroUint32.min(a, b)).toBe(500000);
|
|
122
|
+
expect(NonZeroUint32.max(a, b)).toBe(1000000);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('add (with clamping to non-zero uint32 range)', () => {
|
|
126
|
+
const result = NonZeroUint32.add(
|
|
127
|
+
asNonZeroUint32(4294967000),
|
|
128
|
+
asNonZeroUint32(1000),
|
|
129
|
+
);
|
|
130
|
+
expect(result).toBe(4294967295); // clamped to max
|
|
131
|
+
expect(NonZeroUint32.add(a, b)).toBe(1500000);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('sub (never goes below 1)', () => {
|
|
135
|
+
expect(NonZeroUint32.sub(a, b)).toBe(500000);
|
|
136
|
+
expect(NonZeroUint32.sub(b, a)).toBe(1); // clamped to 1
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('mul (with clamping to non-zero uint32 range)', () => {
|
|
140
|
+
const result = NonZeroUint32.mul(
|
|
141
|
+
asNonZeroUint32(100000),
|
|
142
|
+
asNonZeroUint32(100000),
|
|
143
|
+
);
|
|
144
|
+
expect(result).toBe(4294967295); // clamped to max
|
|
145
|
+
expect(NonZeroUint32.mul(asNonZeroUint32(1000), asNonZeroUint32(5))).toBe(
|
|
146
|
+
5000,
|
|
147
|
+
);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('div (floor division, never goes below 1)', () => {
|
|
151
|
+
expect(NonZeroUint32.div(a, asNonZeroUint32(500000))).toBe(2);
|
|
152
|
+
expect(NonZeroUint32.div(asNonZeroUint32(7), asNonZeroUint32(3))).toBe(2);
|
|
153
|
+
expect(
|
|
154
|
+
NonZeroUint32.div(asNonZeroUint32(500000), asNonZeroUint32(1000000)),
|
|
155
|
+
).toBe(1); // floor(500000/1000000) = 0, clamped to 1
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('pow (with clamping to non-zero uint32 range)', () => {
|
|
159
|
+
const result = NonZeroUint32.pow(
|
|
160
|
+
asNonZeroUint32(10000),
|
|
161
|
+
asNonZeroUint32(3),
|
|
162
|
+
);
|
|
163
|
+
expect(result).toBe(4294967295); // clamped to max
|
|
164
|
+
expect(NonZeroUint32.pow(asNonZeroUint32(2), asNonZeroUint32(3))).toBe(8);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('random', () => {
|
|
169
|
+
test('generates non-zero uint32 values within specified range', () => {
|
|
170
|
+
const min = 1;
|
|
171
|
+
const max = 20;
|
|
172
|
+
|
|
173
|
+
for (let i = 0; i < 10; i++) {
|
|
174
|
+
const result = NonZeroUint32.random(min, max);
|
|
175
|
+
expect(result).toBeGreaterThanOrEqual(min);
|
|
176
|
+
expect(result).toBeLessThanOrEqual(max);
|
|
177
|
+
expect(NonZeroUint32.is(result)).toBe(true);
|
|
178
|
+
expect(Number.isInteger(result)).toBe(true);
|
|
179
|
+
expect(result).not.toBe(0);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test('generates values within NonZeroUint32 range', () => {
|
|
184
|
+
for (let i = 0; i < 10; i++) {
|
|
185
|
+
const result = NonZeroUint32.random(1, 30);
|
|
186
|
+
expect(result).toBeGreaterThanOrEqual(1);
|
|
187
|
+
expect(result).toBeLessThanOrEqual(4294967295);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe('type assertions', () => {
|
|
193
|
+
test('type relationships', () => {
|
|
194
|
+
expectType<NonZeroUint32, number>('<=');
|
|
195
|
+
|
|
196
|
+
expectTypeOf(asNonZeroUint32(1000000)).toExtend<NonZeroUint32>();
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = PositiveFiniteNumber;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'a positive finite number';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
MIN_VALUE,
|
|
10
|
+
min: min_,
|
|
11
|
+
max: max_,
|
|
12
|
+
pow,
|
|
13
|
+
add,
|
|
14
|
+
sub,
|
|
15
|
+
mul,
|
|
16
|
+
div,
|
|
17
|
+
random,
|
|
18
|
+
is,
|
|
19
|
+
castType,
|
|
20
|
+
clamp,
|
|
21
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForFloat<
|
|
22
|
+
ElementType,
|
|
23
|
+
number,
|
|
24
|
+
undefined
|
|
25
|
+
>({
|
|
26
|
+
MIN_VALUE: Number.MIN_VALUE,
|
|
27
|
+
MAX_VALUE: undefined,
|
|
28
|
+
typeNameInMessage,
|
|
29
|
+
} as const);
|
|
30
|
+
|
|
31
|
+
const floor = (
|
|
32
|
+
x: ElementType,
|
|
33
|
+
): TsVerifiedInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
34
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
35
|
+
> =>
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
37
|
+
Math.floor(x) as TsVerifiedInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
38
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
39
|
+
>;
|
|
40
|
+
|
|
41
|
+
const ceil = (
|
|
42
|
+
x: ElementType,
|
|
43
|
+
): TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType> =>
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
45
|
+
Math.ceil(x) as TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>;
|
|
46
|
+
|
|
47
|
+
const round = (
|
|
48
|
+
x: ElementType,
|
|
49
|
+
): TsVerifiedInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
50
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
51
|
+
> =>
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
53
|
+
Math.round(x) as TsVerifiedInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
54
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
55
|
+
>;
|
|
56
|
+
|
|
57
|
+
expectType<
|
|
58
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>,
|
|
59
|
+
PositiveInt
|
|
60
|
+
>('=');
|
|
61
|
+
|
|
62
|
+
expectType<
|
|
63
|
+
TsVerifiedInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
64
|
+
TsVerifiedInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
65
|
+
>,
|
|
66
|
+
Uint
|
|
67
|
+
>('=');
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Checks if a number is a PositiveFiniteNumber (a finite number > 0).
|
|
71
|
+
* @param value The value to check.
|
|
72
|
+
* @returns `true` if the value is a PositiveFiniteNumber, `false` otherwise.
|
|
73
|
+
*/
|
|
74
|
+
export const isPositiveFiniteNumber = is;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Casts a number to a PositiveFiniteNumber type.
|
|
78
|
+
* @param value The value to cast.
|
|
79
|
+
* @returns The value as a PositiveFiniteNumber type.
|
|
80
|
+
* @throws {TypeError} If the value is not a positive finite number.
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const x = asPositiveFiniteNumber(5.5); // PositiveFiniteNumber
|
|
84
|
+
* const y = asPositiveFiniteNumber(0.001); // PositiveFiniteNumber
|
|
85
|
+
* // asPositiveFiniteNumber(0); // throws TypeError
|
|
86
|
+
* // asPositiveFiniteNumber(-1); // throws TypeError
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export const asPositiveFiniteNumber = castType;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Namespace providing type-safe arithmetic operations for positive finite numbers.
|
|
93
|
+
*
|
|
94
|
+
* All operations maintain the positive constraint by clamping non-positive results to MIN_VALUE,
|
|
95
|
+
* while ensuring results remain finite (excluding NaN and Infinity). This type is useful
|
|
96
|
+
* for representing quantities that must always be positive, such as probabilities, magnitudes,
|
|
97
|
+
* and physical measurements.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const probability = asPositiveFiniteNumber(0.75);
|
|
102
|
+
* const rate = asPositiveFiniteNumber(1.25);
|
|
103
|
+
*
|
|
104
|
+
* // Arithmetic operations with positive clamping
|
|
105
|
+
* const combined = PositiveFiniteNumber.add(probability, rate); // PositiveFiniteNumber (2.0)
|
|
106
|
+
* const difference = PositiveFiniteNumber.sub(rate, probability); // PositiveFiniteNumber (0.5)
|
|
107
|
+
* const scaled = PositiveFiniteNumber.mul(probability, rate); // PositiveFiniteNumber (0.9375)
|
|
108
|
+
* const ratio = PositiveFiniteNumber.div(rate, probability); // PositiveFiniteNumber (1.666...)
|
|
109
|
+
*
|
|
110
|
+
* // Range operations
|
|
111
|
+
* const clamped = PositiveFiniteNumber.clamp(-10.5); // PositiveFiniteNumber (MIN_VALUE)
|
|
112
|
+
* const minimum = PositiveFiniteNumber.min(probability, rate); // PositiveFiniteNumber (0.75)
|
|
113
|
+
* const maximum = PositiveFiniteNumber.max(probability, rate); // PositiveFiniteNumber (1.25)
|
|
114
|
+
*
|
|
115
|
+
* // Rounding operations (different return types based on operation)
|
|
116
|
+
* const ceiled = PositiveFiniteNumber.ceil(probability); // PositiveInt (1)
|
|
117
|
+
* const floored = PositiveFiniteNumber.floor(rate); // Uint (1)
|
|
118
|
+
* const rounded = PositiveFiniteNumber.round(rate); // Uint (1)
|
|
119
|
+
*
|
|
120
|
+
* // Utility operations
|
|
121
|
+
* const random = PositiveFiniteNumber.random(); // PositiveFiniteNumber (random positive value)
|
|
122
|
+
* const power = PositiveFiniteNumber.pow(rate, probability); // PositiveFiniteNumber (1.18...)
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export const PositiveFiniteNumber = {
|
|
126
|
+
/**
|
|
127
|
+
* Type guard to check if a value is a PositiveFiniteNumber.
|
|
128
|
+
* @param value The value to check.
|
|
129
|
+
* @returns `true` if the value is a positive finite number, `false` otherwise.
|
|
130
|
+
*/
|
|
131
|
+
is,
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* The minimum value for a positive finite number.
|
|
135
|
+
* @readonly
|
|
136
|
+
*/
|
|
137
|
+
MIN_VALUE,
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns the smaller of two PositiveFiniteNumber values.
|
|
141
|
+
* @param a The first PositiveFiniteNumber.
|
|
142
|
+
* @param b The second PositiveFiniteNumber.
|
|
143
|
+
* @returns The minimum value as a PositiveFiniteNumber.
|
|
144
|
+
*/
|
|
145
|
+
min: min_,
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Returns the larger of two PositiveFiniteNumber values.
|
|
149
|
+
* @param a The first PositiveFiniteNumber.
|
|
150
|
+
* @param b The second PositiveFiniteNumber.
|
|
151
|
+
* @returns The maximum value as a PositiveFiniteNumber.
|
|
152
|
+
*/
|
|
153
|
+
max: max_,
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Clamps a number to the positive finite range.
|
|
157
|
+
* @param value The number to clamp.
|
|
158
|
+
* @returns The value clamped to (0, +∞) as a PositiveFiniteNumber.
|
|
159
|
+
*/
|
|
160
|
+
clamp,
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Rounds down a PositiveFiniteNumber to the nearest integer.
|
|
164
|
+
* @param x The PositiveFiniteNumber to round down.
|
|
165
|
+
* @returns The floor value as a Uint (can be 0).
|
|
166
|
+
*/
|
|
167
|
+
floor,
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Rounds up a PositiveFiniteNumber to the nearest integer.
|
|
171
|
+
* @param x The PositiveFiniteNumber to round up.
|
|
172
|
+
* @returns The ceiling value as a PositiveInt (always >= 1).
|
|
173
|
+
*/
|
|
174
|
+
ceil,
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Rounds a PositiveFiniteNumber to the nearest integer.
|
|
178
|
+
* @param x The PositiveFiniteNumber to round.
|
|
179
|
+
* @returns The rounded value as a Uint (can be 0 if x < 0.5).
|
|
180
|
+
*/
|
|
181
|
+
round,
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Generates a random PositiveFiniteNumber value.
|
|
185
|
+
* @returns A random positive finite number.
|
|
186
|
+
*/
|
|
187
|
+
random,
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Raises a PositiveFiniteNumber to the power of another PositiveFiniteNumber.
|
|
191
|
+
* @param a The base PositiveFiniteNumber.
|
|
192
|
+
* @param b The exponent PositiveFiniteNumber.
|
|
193
|
+
* @returns `a ** b` clamped to (0, +∞) as a PositiveFiniteNumber.
|
|
194
|
+
*/
|
|
195
|
+
pow,
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Adds two PositiveFiniteNumber values.
|
|
199
|
+
* @param a The first PositiveFiniteNumber.
|
|
200
|
+
* @param b The second PositiveFiniteNumber.
|
|
201
|
+
* @returns `a + b` clamped to (0, +∞) as a PositiveFiniteNumber.
|
|
202
|
+
*/
|
|
203
|
+
add,
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Subtracts one PositiveFiniteNumber from another.
|
|
207
|
+
* @param a The minuend PositiveFiniteNumber.
|
|
208
|
+
* @param b The subtrahend PositiveFiniteNumber.
|
|
209
|
+
* @returns `a - b` clamped to (0, +∞) as a PositiveFiniteNumber (minimum MIN_VALUE).
|
|
210
|
+
*/
|
|
211
|
+
sub,
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Multiplies two PositiveFiniteNumber values.
|
|
215
|
+
* @param a The first PositiveFiniteNumber.
|
|
216
|
+
* @param b The second PositiveFiniteNumber.
|
|
217
|
+
* @returns `a * b` clamped to (0, +∞) as a PositiveFiniteNumber.
|
|
218
|
+
*/
|
|
219
|
+
mul,
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Divides one PositiveFiniteNumber by another.
|
|
223
|
+
* @param a The dividend PositiveFiniteNumber.
|
|
224
|
+
* @param b The divisor PositiveFiniteNumber.
|
|
225
|
+
* @returns `a / b` clamped to (0, +∞) as a PositiveFiniteNumber.
|
|
226
|
+
*/
|
|
227
|
+
div,
|
|
228
|
+
} as const;
|
|
229
|
+
|
|
230
|
+
expectType<
|
|
231
|
+
keyof typeof PositiveFiniteNumber,
|
|
232
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
233
|
+
ElementType,
|
|
234
|
+
'positive'
|
|
235
|
+
>
|
|
236
|
+
>('=');
|
|
237
|
+
|
|
238
|
+
expectType<
|
|
239
|
+
typeof PositiveFiniteNumber,
|
|
240
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<ElementType, 'positive'>
|
|
241
|
+
>('<=');
|