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,196 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = NonZeroInt32;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'a non-zero integer in [-2^31, 2^31)';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
MIN_VALUE,
|
|
10
|
+
MAX_VALUE,
|
|
11
|
+
abs,
|
|
12
|
+
min: min_,
|
|
13
|
+
max: max_,
|
|
14
|
+
pow,
|
|
15
|
+
add,
|
|
16
|
+
sub,
|
|
17
|
+
mul,
|
|
18
|
+
div,
|
|
19
|
+
randomNonZero: random,
|
|
20
|
+
is,
|
|
21
|
+
castType,
|
|
22
|
+
clamp,
|
|
23
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForInteger<
|
|
24
|
+
ElementType,
|
|
25
|
+
number,
|
|
26
|
+
number
|
|
27
|
+
>({
|
|
28
|
+
integerOrSafeInteger: 'SafeInteger',
|
|
29
|
+
nonZero: true,
|
|
30
|
+
MIN_VALUE: -(2 ** 31),
|
|
31
|
+
MAX_VALUE: 2 ** 31 - 1,
|
|
32
|
+
typeNameInMessage,
|
|
33
|
+
} as const);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a number is a NonZeroInt32 (32-bit non-zero signed integer in the range [-2^31, 2^31) excluding 0).
|
|
37
|
+
* @param value The value to check.
|
|
38
|
+
* @returns `true` if the value is a NonZeroInt32, `false` otherwise.
|
|
39
|
+
*/
|
|
40
|
+
export const isNonZeroInt32 = is;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Casts a number to a NonZeroInt32 type.
|
|
44
|
+
* @param value The value to cast.
|
|
45
|
+
* @returns The value as a NonZeroInt32 type.
|
|
46
|
+
* @throws {TypeError} If the value is not a non-zero integer in [-2^31, 2^31).
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const x = asNonZeroInt32(1000); // NonZeroInt32
|
|
50
|
+
* const y = asNonZeroInt32(-1000); // NonZeroInt32
|
|
51
|
+
* // asNonZeroInt32(0); // throws TypeError
|
|
52
|
+
* // asNonZeroInt32(2147483648); // throws TypeError
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const asNonZeroInt32 = castType;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Namespace providing type-safe arithmetic operations for 32-bit non-zero signed integers.
|
|
59
|
+
*
|
|
60
|
+
* All operations automatically clamp results to the valid NonZeroInt32 range [-2147483648, 2147483647]
|
|
61
|
+
* excluding 0. This ensures that all arithmetic maintains the 32-bit non-zero signed integer
|
|
62
|
+
* constraint, preventing zero results and overflow.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const a = asNonZeroInt32(2000000000);
|
|
67
|
+
* const b = asNonZeroInt32(-500000000);
|
|
68
|
+
*
|
|
69
|
+
* // Arithmetic operations with automatic clamping and non-zero constraint
|
|
70
|
+
* const sum = NonZeroInt32.add(a, b); // NonZeroInt32 (1500000000)
|
|
71
|
+
* const diff = NonZeroInt32.sub(a, b); // NonZeroInt32 (2147483647 - clamped to MAX_VALUE)
|
|
72
|
+
* const product = NonZeroInt32.mul(a, b); // NonZeroInt32 (-2147483648 - clamped to MIN_VALUE)
|
|
73
|
+
*
|
|
74
|
+
* // Utility operations
|
|
75
|
+
* const absolute = NonZeroInt32.abs(b); // NonZeroInt32 (500000000)
|
|
76
|
+
* const minimum = NonZeroInt32.min(a, b); // NonZeroInt32 (-500000000)
|
|
77
|
+
* const maximum = NonZeroInt32.max(a, b); // NonZeroInt32 (2000000000)
|
|
78
|
+
*
|
|
79
|
+
* // Range operations (avoiding zero)
|
|
80
|
+
* const clamped = NonZeroInt32.clamp(0); // NonZeroInt32 (1 or -1, avoiding zero)
|
|
81
|
+
* const random = NonZeroInt32.random(); // NonZeroInt32 (random non-zero value in range)
|
|
82
|
+
* const power = NonZeroInt32.pow(asNonZeroInt32(2), asNonZeroInt32(20)); // NonZeroInt32 (1048576)
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export const NonZeroInt32 = {
|
|
86
|
+
/**
|
|
87
|
+
* Type guard to check if a value is a NonZeroInt32.
|
|
88
|
+
* @param value The value to check.
|
|
89
|
+
* @returns `true` if the value is a 32-bit non-zero signed integer, `false` otherwise.
|
|
90
|
+
*/
|
|
91
|
+
is,
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The minimum value for a 32-bit non-zero signed integer.
|
|
95
|
+
* @readonly
|
|
96
|
+
*/
|
|
97
|
+
MIN_VALUE,
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The maximum value for a 32-bit non-zero signed integer.
|
|
101
|
+
* @readonly
|
|
102
|
+
*/
|
|
103
|
+
MAX_VALUE,
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns the absolute value of a 32-bit non-zero signed integer.
|
|
107
|
+
* @param a The NonZeroInt32 value.
|
|
108
|
+
* @returns The absolute value as a NonZeroInt32, clamped to valid range.
|
|
109
|
+
*/
|
|
110
|
+
abs,
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns the smaller of two NonZeroInt32 values.
|
|
114
|
+
* @param a The first NonZeroInt32.
|
|
115
|
+
* @param b The second NonZeroInt32.
|
|
116
|
+
* @returns The minimum value as a NonZeroInt32.
|
|
117
|
+
*/
|
|
118
|
+
min: min_,
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Returns the larger of two NonZeroInt32 values.
|
|
122
|
+
* @param a The first NonZeroInt32.
|
|
123
|
+
* @param b The second NonZeroInt32.
|
|
124
|
+
* @returns The maximum value as a NonZeroInt32.
|
|
125
|
+
*/
|
|
126
|
+
max: max_,
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Clamps a number to the NonZeroInt32 range (avoiding zero).
|
|
130
|
+
* @param value The number to clamp.
|
|
131
|
+
* @returns The value clamped to [-2147483648, 2147483647] \ {0} as a NonZeroInt32.
|
|
132
|
+
*/
|
|
133
|
+
clamp,
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generates a random NonZeroInt32 value within the valid range.
|
|
137
|
+
* @returns A random NonZeroInt32 between MIN_VALUE and MAX_VALUE (excluding 0).
|
|
138
|
+
*/
|
|
139
|
+
random,
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Raises a NonZeroInt32 to the power of another NonZeroInt32.
|
|
143
|
+
* @param a The base NonZeroInt32.
|
|
144
|
+
* @param b The exponent NonZeroInt32.
|
|
145
|
+
* @returns `a ** b` clamped to [-2147483648, 2147483647] as a NonZeroInt32.
|
|
146
|
+
*/
|
|
147
|
+
pow,
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Adds two NonZeroInt32 values.
|
|
151
|
+
* @param a The first NonZeroInt32.
|
|
152
|
+
* @param b The second NonZeroInt32.
|
|
153
|
+
* @returns `a + b` clamped to [-2147483648, 2147483647] as a NonZeroInt32.
|
|
154
|
+
*/
|
|
155
|
+
add,
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Subtracts one NonZeroInt32 from another.
|
|
159
|
+
* @param a The minuend NonZeroInt32.
|
|
160
|
+
* @param b The subtrahend NonZeroInt32.
|
|
161
|
+
* @returns `a - b` clamped to [-2147483648, 2147483647] as a NonZeroInt32.
|
|
162
|
+
*/
|
|
163
|
+
sub,
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Multiplies two NonZeroInt32 values.
|
|
167
|
+
* @param a The first NonZeroInt32.
|
|
168
|
+
* @param b The second NonZeroInt32.
|
|
169
|
+
* @returns `a * b` clamped to [-2147483648, 2147483647] as a NonZeroInt32.
|
|
170
|
+
*/
|
|
171
|
+
mul,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Divides one NonZeroInt32 by another using floor division.
|
|
175
|
+
* @param a The dividend NonZeroInt32.
|
|
176
|
+
* @param b The divisor NonZeroInt32.
|
|
177
|
+
* @returns `⌊a / b⌋` clamped to [-2147483648, 2147483647] as a NonZeroInt32.
|
|
178
|
+
*/
|
|
179
|
+
div,
|
|
180
|
+
} as const;
|
|
181
|
+
|
|
182
|
+
expectType<
|
|
183
|
+
keyof typeof NonZeroInt32,
|
|
184
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
185
|
+
ElementType,
|
|
186
|
+
'int' | 'range'
|
|
187
|
+
>
|
|
188
|
+
>('=');
|
|
189
|
+
|
|
190
|
+
expectType<
|
|
191
|
+
typeof NonZeroInt32,
|
|
192
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
193
|
+
ElementType,
|
|
194
|
+
'int' | 'range'
|
|
195
|
+
>
|
|
196
|
+
>('<=');
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import {
|
|
3
|
+
asNonZeroInt32,
|
|
4
|
+
isNonZeroInt32,
|
|
5
|
+
NonZeroInt32,
|
|
6
|
+
} from './non-zero-int32.mjs';
|
|
7
|
+
|
|
8
|
+
describe('NonZeroInt32', () => {
|
|
9
|
+
describe('asNonZeroInt32', () => {
|
|
10
|
+
test('accepts valid non-zero int32 values', () => {
|
|
11
|
+
expect(() => asNonZeroInt32(1)).not.toThrow();
|
|
12
|
+
expect(() => asNonZeroInt32(-1)).not.toThrow();
|
|
13
|
+
expect(() => asNonZeroInt32(2147483647)).not.toThrow(); // 2^31 - 1
|
|
14
|
+
expect(() => asNonZeroInt32(-2147483648)).not.toThrow(); // -2^31
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('rejects zero', () => {
|
|
18
|
+
expect(() => asNonZeroInt32(0)).toThrow(TypeError);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('rejects values outside int32 range', () => {
|
|
22
|
+
expect(() => asNonZeroInt32(2147483648)).toThrow(TypeError); // 2^31
|
|
23
|
+
expect(() => asNonZeroInt32(-2147483649)).toThrow(TypeError); // -2^31 - 1
|
|
24
|
+
expect(() => asNonZeroInt32(4294967296)).toThrow(TypeError);
|
|
25
|
+
expect(() => asNonZeroInt32(-4294967296)).toThrow(TypeError);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('rejects non-integers', () => {
|
|
29
|
+
expect(() => asNonZeroInt32(Number.NaN)).toThrow(TypeError);
|
|
30
|
+
expect(() => asNonZeroInt32(Number.POSITIVE_INFINITY)).toThrow(TypeError);
|
|
31
|
+
expect(() => asNonZeroInt32(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
32
|
+
expect(() => asNonZeroInt32(1.2)).toThrow(TypeError);
|
|
33
|
+
expect(() => asNonZeroInt32(-3.4)).toThrow(TypeError);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('returns the same value for valid inputs', () => {
|
|
37
|
+
expect(asNonZeroInt32(5)).toBe(5);
|
|
38
|
+
expect(asNonZeroInt32(-10)).toBe(-10);
|
|
39
|
+
expect(asNonZeroInt32(2147483647)).toBe(2147483647);
|
|
40
|
+
expect(asNonZeroInt32(-2147483648)).toBe(-2147483648);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test.each([
|
|
44
|
+
{ name: 'Number.NaN', value: Number.NaN },
|
|
45
|
+
{ name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
|
|
46
|
+
{ name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
|
|
47
|
+
{ name: '1.2', value: 1.2 },
|
|
48
|
+
{ name: '-3.4', value: -3.4 },
|
|
49
|
+
{ name: '0', value: 0 },
|
|
50
|
+
{ name: '2147483648', value: 2147483648 },
|
|
51
|
+
{ name: '-2147483649', value: -2147483649 },
|
|
52
|
+
] as const)(
|
|
53
|
+
`asNonZeroInt32($name) should throw a TypeError`,
|
|
54
|
+
({ value }) => {
|
|
55
|
+
expect(() => asNonZeroInt32(value)).toThrow(
|
|
56
|
+
new TypeError(
|
|
57
|
+
`Expected a non-zero integer in [-2^31, 2^31), got: ${value}`,
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('isNonZeroInt32', () => {
|
|
65
|
+
test('correctly identifies non-zero int32 values', () => {
|
|
66
|
+
expect(isNonZeroInt32(1)).toBe(true);
|
|
67
|
+
expect(isNonZeroInt32(-1)).toBe(true);
|
|
68
|
+
expect(isNonZeroInt32(2147483647)).toBe(true);
|
|
69
|
+
expect(isNonZeroInt32(-2147483648)).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('correctly identifies zero', () => {
|
|
73
|
+
expect(isNonZeroInt32(0)).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('correctly identifies values outside int32 range', () => {
|
|
77
|
+
expect(isNonZeroInt32(2147483648)).toBe(false);
|
|
78
|
+
expect(isNonZeroInt32(-2147483649)).toBe(false);
|
|
79
|
+
expect(isNonZeroInt32(4294967296)).toBe(false);
|
|
80
|
+
expect(isNonZeroInt32(-4294967296)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('correctly identifies non-integers', () => {
|
|
84
|
+
expect(isNonZeroInt32(Number.NaN)).toBe(false);
|
|
85
|
+
expect(isNonZeroInt32(Number.POSITIVE_INFINITY)).toBe(false);
|
|
86
|
+
expect(isNonZeroInt32(Number.NEGATIVE_INFINITY)).toBe(false);
|
|
87
|
+
expect(isNonZeroInt32(1.2)).toBe(false);
|
|
88
|
+
expect(isNonZeroInt32(-3.4)).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('NonZeroInt32.is', () => {
|
|
93
|
+
test('same as isNonZeroInt32 function', () => {
|
|
94
|
+
expect(NonZeroInt32.is(5)).toBe(isNonZeroInt32(5));
|
|
95
|
+
expect(NonZeroInt32.is(0)).toBe(isNonZeroInt32(0));
|
|
96
|
+
expect(NonZeroInt32.is(-1)).toBe(isNonZeroInt32(-1));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('constants', () => {
|
|
101
|
+
test('MIN_VALUE and MAX_VALUE', () => {
|
|
102
|
+
expect(NonZeroInt32.MIN_VALUE).toBe(-2147483648);
|
|
103
|
+
expect(NonZeroInt32.MAX_VALUE).toBe(2147483647);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('mathematical operations', () => {
|
|
108
|
+
const a = asNonZeroInt32(1000000);
|
|
109
|
+
const b = asNonZeroInt32(500000);
|
|
110
|
+
const c = asNonZeroInt32(-300000);
|
|
111
|
+
|
|
112
|
+
test('abs', () => {
|
|
113
|
+
expect(NonZeroInt32.abs(a)).toBe(1000000);
|
|
114
|
+
expect(NonZeroInt32.abs(c)).toBe(300000);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('min and max', () => {
|
|
118
|
+
expect(NonZeroInt32.min(a, b)).toBe(500000);
|
|
119
|
+
expect(NonZeroInt32.max(a, b)).toBe(1000000);
|
|
120
|
+
expect(NonZeroInt32.min(a, c)).toBe(-300000);
|
|
121
|
+
expect(NonZeroInt32.max(a, c)).toBe(1000000);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('add (with clamping)', () => {
|
|
125
|
+
const result = NonZeroInt32.add(
|
|
126
|
+
asNonZeroInt32(2147483000),
|
|
127
|
+
asNonZeroInt32(1000),
|
|
128
|
+
);
|
|
129
|
+
expect(result).toBe(2147483647); // clamped to max
|
|
130
|
+
expect(NonZeroInt32.add(a, b)).toBe(1500000);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('sub (with clamping)', () => {
|
|
134
|
+
const result = NonZeroInt32.sub(
|
|
135
|
+
asNonZeroInt32(-2147483000),
|
|
136
|
+
asNonZeroInt32(1000),
|
|
137
|
+
);
|
|
138
|
+
expect(result).toBe(-2147483648); // clamped to min
|
|
139
|
+
expect(NonZeroInt32.sub(a, b)).toBe(500000);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('mul (with clamping)', () => {
|
|
143
|
+
const result = NonZeroInt32.mul(
|
|
144
|
+
asNonZeroInt32(100000),
|
|
145
|
+
asNonZeroInt32(100000),
|
|
146
|
+
);
|
|
147
|
+
expect(result).toBe(2147483647); // clamped to max
|
|
148
|
+
expect(NonZeroInt32.mul(asNonZeroInt32(1000), asNonZeroInt32(5))).toBe(
|
|
149
|
+
5000,
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('div (floor division with clamping)', () => {
|
|
154
|
+
expect(NonZeroInt32.div(a, asNonZeroInt32(500000))).toBe(2);
|
|
155
|
+
expect(NonZeroInt32.div(asNonZeroInt32(7), asNonZeroInt32(3))).toBe(2);
|
|
156
|
+
expect(NonZeroInt32.div(asNonZeroInt32(-7), asNonZeroInt32(3))).toBe(-3);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('pow (with clamping)', () => {
|
|
160
|
+
const result = NonZeroInt32.pow(asNonZeroInt32(10000), asNonZeroInt32(3));
|
|
161
|
+
expect(result).toBe(2147483647); // clamped to max
|
|
162
|
+
expect(NonZeroInt32.pow(asNonZeroInt32(2), asNonZeroInt32(3))).toBe(8);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('random', () => {
|
|
167
|
+
test('generates non-zero int32 values within specified range', () => {
|
|
168
|
+
const min = -10;
|
|
169
|
+
const max = 10;
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < 10; i++) {
|
|
172
|
+
const result = NonZeroInt32.random(min, max);
|
|
173
|
+
expect(result).toBeGreaterThanOrEqual(min);
|
|
174
|
+
expect(result).toBeLessThanOrEqual(max);
|
|
175
|
+
expect(NonZeroInt32.is(result)).toBe(true);
|
|
176
|
+
expect(Number.isInteger(result)).toBe(true);
|
|
177
|
+
expect(result).not.toBe(0);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('generates values within NonZeroInt32 range', () => {
|
|
182
|
+
for (let i = 0; i < 10; i++) {
|
|
183
|
+
const result = NonZeroInt32.random(-20, 20);
|
|
184
|
+
expect(result).toBeGreaterThanOrEqual(-2147483648);
|
|
185
|
+
expect(result).toBeLessThanOrEqual(2147483647);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('type assertions', () => {
|
|
191
|
+
test('type relationships', () => {
|
|
192
|
+
expectType<NonZeroInt32, number>('<=');
|
|
193
|
+
|
|
194
|
+
expectTypeOf(asNonZeroInt32(1000000)).toExtend<NonZeroInt32>();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { expectType } from '../../expect-type.mjs';
|
|
2
|
+
import { TsVerifiedInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
type ElementType = NonZeroSafeInt;
|
|
5
|
+
|
|
6
|
+
const typeNameInMessage = 'a non-zero safe integer';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
MIN_VALUE,
|
|
10
|
+
MAX_VALUE,
|
|
11
|
+
abs,
|
|
12
|
+
min: min_,
|
|
13
|
+
max: max_,
|
|
14
|
+
pow,
|
|
15
|
+
add,
|
|
16
|
+
sub,
|
|
17
|
+
mul,
|
|
18
|
+
div,
|
|
19
|
+
randomNonZero: random,
|
|
20
|
+
is,
|
|
21
|
+
castType,
|
|
22
|
+
clamp,
|
|
23
|
+
} = TsVerifiedInternals.RefinedNumberUtils.operatorsForInteger<
|
|
24
|
+
ElementType,
|
|
25
|
+
SafeInt,
|
|
26
|
+
SafeUint
|
|
27
|
+
>({
|
|
28
|
+
integerOrSafeInteger: 'SafeInteger',
|
|
29
|
+
nonZero: true,
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
31
|
+
MIN_VALUE: Number.MIN_SAFE_INTEGER as SafeInt,
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
33
|
+
MAX_VALUE: Number.MAX_SAFE_INTEGER as SafeUint,
|
|
34
|
+
typeNameInMessage,
|
|
35
|
+
} as const);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Checks if a number is a NonZeroSafeInt (a non-zero safe integer in the range [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] excluding 0).
|
|
39
|
+
* @param value The value to check.
|
|
40
|
+
* @returns `true` if the value is a NonZeroSafeInt, `false` otherwise.
|
|
41
|
+
*/
|
|
42
|
+
export const isNonZeroSafeInt = is;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Casts a number to a NonZeroSafeInt type.
|
|
46
|
+
* @param value The value to cast.
|
|
47
|
+
* @returns The value as a NonZeroSafeInt type.
|
|
48
|
+
* @throws {TypeError} If the value is not a non-zero safe integer.
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const x = asNonZeroSafeInt(5); // NonZeroSafeInt
|
|
52
|
+
* const y = asNonZeroSafeInt(-1000); // NonZeroSafeInt
|
|
53
|
+
* // asNonZeroSafeInt(0); // throws TypeError
|
|
54
|
+
* // asNonZeroSafeInt(1.5); // throws TypeError
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export const asNonZeroSafeInt = castType;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Namespace providing type-safe arithmetic operations for non-zero safe integers.
|
|
61
|
+
*
|
|
62
|
+
* All operations automatically clamp results to the non-zero safe integer range, excluding zero.
|
|
63
|
+
* This ensures that all arithmetic maintains both the non-zero constraint and IEEE 754 precision guarantees,
|
|
64
|
+
* preventing precision loss while ensuring results are never zero.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const a = asNonZeroSafeInt(9007199254740000); // Near MAX_SAFE_INTEGER
|
|
69
|
+
* const b = asNonZeroSafeInt(-1000);
|
|
70
|
+
*
|
|
71
|
+
* // Arithmetic operations with non-zero safe range clamping
|
|
72
|
+
* const sum = NonZeroSafeInt.add(a, b); // NonZeroSafeInt (9007199254739000)
|
|
73
|
+
* const diff = NonZeroSafeInt.sub(a, b); // NonZeroSafeInt (clamped to MAX_SAFE_INTEGER)
|
|
74
|
+
* const product = NonZeroSafeInt.mul(a, b); // NonZeroSafeInt (clamped to MIN_SAFE_INTEGER)
|
|
75
|
+
*
|
|
76
|
+
* // Utility operations
|
|
77
|
+
* const absolute = NonZeroSafeInt.abs(b); // NonZeroSafeInt (1000)
|
|
78
|
+
* const minimum = NonZeroSafeInt.min(a, b); // NonZeroSafeInt (-1000)
|
|
79
|
+
* const maximum = NonZeroSafeInt.max(a, b); // NonZeroSafeInt (a)
|
|
80
|
+
*
|
|
81
|
+
* // Random generation
|
|
82
|
+
* const random = NonZeroSafeInt.random(); // NonZeroSafeInt (random non-zero safe integer)
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export const NonZeroSafeInt = {
|
|
86
|
+
/**
|
|
87
|
+
* Type guard to check if a value is a NonZeroSafeInt.
|
|
88
|
+
* @param value The value to check.
|
|
89
|
+
* @returns `true` if the value is a non-zero safe integer, `false` otherwise.
|
|
90
|
+
*/
|
|
91
|
+
is,
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The minimum safe integer value (-(2^53 - 1)).
|
|
95
|
+
* @readonly
|
|
96
|
+
*/
|
|
97
|
+
MIN_VALUE,
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The maximum safe integer value (2^53 - 1).
|
|
101
|
+
* @readonly
|
|
102
|
+
*/
|
|
103
|
+
MAX_VALUE,
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns the absolute value of a non-zero safe integer.
|
|
107
|
+
* @param a The NonZeroSafeInt value.
|
|
108
|
+
* @returns The absolute value as a NonZeroSafeInt, clamped to safe range.
|
|
109
|
+
*/
|
|
110
|
+
abs,
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Returns the smaller of two NonZeroSafeInt values.
|
|
114
|
+
* @param a The first NonZeroSafeInt.
|
|
115
|
+
* @param b The second NonZeroSafeInt.
|
|
116
|
+
* @returns The minimum value as a NonZeroSafeInt.
|
|
117
|
+
*/
|
|
118
|
+
min: min_,
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Returns the larger of two NonZeroSafeInt values.
|
|
122
|
+
* @param a The first NonZeroSafeInt.
|
|
123
|
+
* @param b The second NonZeroSafeInt.
|
|
124
|
+
* @returns The maximum value as a NonZeroSafeInt.
|
|
125
|
+
*/
|
|
126
|
+
max: max_,
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Clamps a number to the non-zero safe integer range.
|
|
130
|
+
* @param value The number to clamp.
|
|
131
|
+
* @returns The value clamped to [MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] \ {0} as a NonZeroSafeInt.
|
|
132
|
+
*/
|
|
133
|
+
clamp,
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generates a random NonZeroSafeInt value within the valid range.
|
|
137
|
+
* @returns A random non-zero safe integer between MIN_SAFE_INTEGER and MAX_SAFE_INTEGER.
|
|
138
|
+
*/
|
|
139
|
+
random,
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Raises a NonZeroSafeInt to the power of another NonZeroSafeInt.
|
|
143
|
+
* @param a The base NonZeroSafeInt.
|
|
144
|
+
* @param b The exponent NonZeroSafeInt.
|
|
145
|
+
* @returns `a ** b` clamped to non-zero safe integer range as a NonZeroSafeInt.
|
|
146
|
+
*/
|
|
147
|
+
pow,
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Adds two NonZeroSafeInt values.
|
|
151
|
+
* @param a The first NonZeroSafeInt.
|
|
152
|
+
* @param b The second NonZeroSafeInt.
|
|
153
|
+
* @returns `a + b` clamped to non-zero safe integer range as a NonZeroSafeInt.
|
|
154
|
+
*/
|
|
155
|
+
add,
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Subtracts one NonZeroSafeInt from another.
|
|
159
|
+
* @param a The minuend NonZeroSafeInt.
|
|
160
|
+
* @param b The subtrahend NonZeroSafeInt.
|
|
161
|
+
* @returns `a - b` clamped to non-zero safe integer range as a NonZeroSafeInt.
|
|
162
|
+
*/
|
|
163
|
+
sub,
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Multiplies two NonZeroSafeInt values.
|
|
167
|
+
* @param a The first NonZeroSafeInt.
|
|
168
|
+
* @param b The second NonZeroSafeInt.
|
|
169
|
+
* @returns `a * b` clamped to non-zero safe integer range as a NonZeroSafeInt.
|
|
170
|
+
*/
|
|
171
|
+
mul,
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Divides one NonZeroSafeInt by another using floor division.
|
|
175
|
+
* @param a The dividend NonZeroSafeInt.
|
|
176
|
+
* @param b The divisor NonZeroSafeInt.
|
|
177
|
+
* @returns `⌊a / b⌋` clamped to non-zero safe integer range as a NonZeroSafeInt.
|
|
178
|
+
*/
|
|
179
|
+
div,
|
|
180
|
+
} as const;
|
|
181
|
+
|
|
182
|
+
expectType<
|
|
183
|
+
keyof typeof NonZeroSafeInt,
|
|
184
|
+
keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
185
|
+
ElementType,
|
|
186
|
+
'int' | 'range'
|
|
187
|
+
>
|
|
188
|
+
>('=');
|
|
189
|
+
|
|
190
|
+
expectType<
|
|
191
|
+
typeof NonZeroSafeInt,
|
|
192
|
+
TsVerifiedInternals.RefinedNumberUtils.NumberClass<
|
|
193
|
+
ElementType,
|
|
194
|
+
'int' | 'range'
|
|
195
|
+
>
|
|
196
|
+
>('<=');
|