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.
Files changed (143) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +534 -0
  3. package/package.json +101 -0
  4. package/src/array/array-utils-creation.test.mts +443 -0
  5. package/src/array/array-utils-modification.test.mts +197 -0
  6. package/src/array/array-utils-overload-type-error.test.mts +149 -0
  7. package/src/array/array-utils-reducing-value.test.mts +425 -0
  8. package/src/array/array-utils-search.test.mts +169 -0
  9. package/src/array/array-utils-set-op.test.mts +335 -0
  10. package/src/array/array-utils-slice-clamped.test.mts +113 -0
  11. package/src/array/array-utils-slicing.test.mts +316 -0
  12. package/src/array/array-utils-transformation.test.mts +790 -0
  13. package/src/array/array-utils-validation.test.mts +492 -0
  14. package/src/array/array-utils.mts +4000 -0
  15. package/src/array/array.test.mts +146 -0
  16. package/src/array/index.mts +2 -0
  17. package/src/array/tuple-utils.mts +519 -0
  18. package/src/array/tuple-utils.test.mts +518 -0
  19. package/src/collections/imap-mapped.mts +801 -0
  20. package/src/collections/imap-mapped.test.mts +860 -0
  21. package/src/collections/imap.mts +651 -0
  22. package/src/collections/imap.test.mts +932 -0
  23. package/src/collections/index.mts +6 -0
  24. package/src/collections/iset-mapped.mts +889 -0
  25. package/src/collections/iset-mapped.test.mts +1187 -0
  26. package/src/collections/iset.mts +682 -0
  27. package/src/collections/iset.test.mts +1084 -0
  28. package/src/collections/queue.mts +390 -0
  29. package/src/collections/queue.test.mts +282 -0
  30. package/src/collections/stack.mts +423 -0
  31. package/src/collections/stack.test.mts +225 -0
  32. package/src/expect-type.mts +206 -0
  33. package/src/functional/index.mts +4 -0
  34. package/src/functional/match.mts +300 -0
  35. package/src/functional/match.test.mts +177 -0
  36. package/src/functional/optional.mts +733 -0
  37. package/src/functional/optional.test.mts +619 -0
  38. package/src/functional/pipe.mts +212 -0
  39. package/src/functional/pipe.test.mts +85 -0
  40. package/src/functional/result.mts +1134 -0
  41. package/src/functional/result.test.mts +777 -0
  42. package/src/globals.d.mts +38 -0
  43. package/src/guard/has-key.mts +119 -0
  44. package/src/guard/has-key.test.mts +219 -0
  45. package/src/guard/index.mts +7 -0
  46. package/src/guard/is-non-empty-string.mts +108 -0
  47. package/src/guard/is-non-empty-string.test.mts +91 -0
  48. package/src/guard/is-non-null-object.mts +106 -0
  49. package/src/guard/is-non-null-object.test.mts +90 -0
  50. package/src/guard/is-primitive.mts +165 -0
  51. package/src/guard/is-primitive.test.mts +102 -0
  52. package/src/guard/is-record.mts +153 -0
  53. package/src/guard/is-record.test.mts +112 -0
  54. package/src/guard/is-type.mts +450 -0
  55. package/src/guard/is-type.test.mts +496 -0
  56. package/src/guard/key-is-in.mts +163 -0
  57. package/src/guard/key-is-in.test.mts +19 -0
  58. package/src/index.mts +10 -0
  59. package/src/iterator/index.mts +1 -0
  60. package/src/iterator/range.mts +120 -0
  61. package/src/iterator/range.test.mts +33 -0
  62. package/src/json/index.mts +1 -0
  63. package/src/json/json.mts +711 -0
  64. package/src/json/json.test.mts +628 -0
  65. package/src/number/branded-types/finite-number.mts +354 -0
  66. package/src/number/branded-types/finite-number.test.mts +135 -0
  67. package/src/number/branded-types/index.mts +26 -0
  68. package/src/number/branded-types/int.mts +278 -0
  69. package/src/number/branded-types/int.test.mts +140 -0
  70. package/src/number/branded-types/int16.mts +192 -0
  71. package/src/number/branded-types/int16.test.mts +170 -0
  72. package/src/number/branded-types/int32.mts +193 -0
  73. package/src/number/branded-types/int32.test.mts +170 -0
  74. package/src/number/branded-types/non-negative-finite-number.mts +223 -0
  75. package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
  76. package/src/number/branded-types/non-negative-int16.mts +187 -0
  77. package/src/number/branded-types/non-negative-int16.test.mts +201 -0
  78. package/src/number/branded-types/non-negative-int32.mts +187 -0
  79. package/src/number/branded-types/non-negative-int32.test.mts +204 -0
  80. package/src/number/branded-types/non-zero-finite-number.mts +229 -0
  81. package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
  82. package/src/number/branded-types/non-zero-int.mts +167 -0
  83. package/src/number/branded-types/non-zero-int.test.mts +177 -0
  84. package/src/number/branded-types/non-zero-int16.mts +196 -0
  85. package/src/number/branded-types/non-zero-int16.test.mts +195 -0
  86. package/src/number/branded-types/non-zero-int32.mts +196 -0
  87. package/src/number/branded-types/non-zero-int32.test.mts +197 -0
  88. package/src/number/branded-types/non-zero-safe-int.mts +196 -0
  89. package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
  90. package/src/number/branded-types/non-zero-uint16.mts +189 -0
  91. package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
  92. package/src/number/branded-types/non-zero-uint32.mts +189 -0
  93. package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
  94. package/src/number/branded-types/positive-finite-number.mts +241 -0
  95. package/src/number/branded-types/positive-finite-number.test.mts +204 -0
  96. package/src/number/branded-types/positive-int.mts +304 -0
  97. package/src/number/branded-types/positive-int.test.mts +176 -0
  98. package/src/number/branded-types/positive-int16.mts +188 -0
  99. package/src/number/branded-types/positive-int16.test.mts +197 -0
  100. package/src/number/branded-types/positive-int32.mts +188 -0
  101. package/src/number/branded-types/positive-int32.test.mts +197 -0
  102. package/src/number/branded-types/positive-safe-int.mts +187 -0
  103. package/src/number/branded-types/positive-safe-int.test.mts +210 -0
  104. package/src/number/branded-types/positive-uint16.mts +188 -0
  105. package/src/number/branded-types/positive-uint16.test.mts +203 -0
  106. package/src/number/branded-types/positive-uint32.mts +188 -0
  107. package/src/number/branded-types/positive-uint32.test.mts +203 -0
  108. package/src/number/branded-types/safe-int.mts +291 -0
  109. package/src/number/branded-types/safe-int.test.mts +170 -0
  110. package/src/number/branded-types/safe-uint.mts +187 -0
  111. package/src/number/branded-types/safe-uint.test.mts +176 -0
  112. package/src/number/branded-types/uint.mts +179 -0
  113. package/src/number/branded-types/uint.test.mts +158 -0
  114. package/src/number/branded-types/uint16.mts +186 -0
  115. package/src/number/branded-types/uint16.test.mts +170 -0
  116. package/src/number/branded-types/uint32.mts +218 -0
  117. package/src/number/branded-types/uint32.test.mts +170 -0
  118. package/src/number/enum/index.mts +2 -0
  119. package/src/number/enum/int8.mts +344 -0
  120. package/src/number/enum/int8.test.mts +180 -0
  121. package/src/number/enum/uint8.mts +293 -0
  122. package/src/number/enum/uint8.test.mts +164 -0
  123. package/src/number/index.mts +4 -0
  124. package/src/number/num.mts +604 -0
  125. package/src/number/num.test.mts +242 -0
  126. package/src/number/refined-number-utils.mts +566 -0
  127. package/src/object/index.mts +1 -0
  128. package/src/object/object.mts +447 -0
  129. package/src/object/object.test.mts +124 -0
  130. package/src/others/cast-mutable.mts +113 -0
  131. package/src/others/cast-readonly.mts +192 -0
  132. package/src/others/cast-readonly.test.mts +89 -0
  133. package/src/others/if-then.mts +98 -0
  134. package/src/others/if-then.test.mts +75 -0
  135. package/src/others/index.mts +7 -0
  136. package/src/others/map-nullable.mts +172 -0
  137. package/src/others/map-nullable.test.mts +297 -0
  138. package/src/others/memoize-function.mts +196 -0
  139. package/src/others/memoize-function.test.mts +168 -0
  140. package/src/others/tuple.mts +160 -0
  141. package/src/others/tuple.test.mts +11 -0
  142. package/src/others/unknown-to-string.mts +215 -0
  143. package/src/others/unknown-to-string.test.mts +114 -0
@@ -0,0 +1,170 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { asInt16, Int16, isInt16 } from './int16.mjs';
3
+ import { asNonZeroInt16 } from './non-zero-int16.mjs';
4
+
5
+ describe('Int16', () => {
6
+ describe('asInt16', () => {
7
+ test('accepts valid int16 values', () => {
8
+ expect(() => asInt16(0)).not.toThrow();
9
+ expect(() => asInt16(1)).not.toThrow();
10
+ expect(() => asInt16(-1)).not.toThrow();
11
+ expect(() => asInt16(32767)).not.toThrow(); // 2^15 - 1
12
+ expect(() => asInt16(-32768)).not.toThrow(); // -2^15
13
+ });
14
+
15
+ test('rejects values outside int16 range', () => {
16
+ expect(() => asInt16(32768)).toThrow(TypeError); // 2^15
17
+ expect(() => asInt16(-32769)).toThrow(TypeError); // -2^15 - 1
18
+ expect(() => asInt16(65536)).toThrow(TypeError);
19
+ expect(() => asInt16(-65536)).toThrow(TypeError);
20
+ });
21
+
22
+ test('rejects non-integers', () => {
23
+ expect(() => asInt16(Number.NaN)).toThrow(TypeError);
24
+ expect(() => asInt16(Number.POSITIVE_INFINITY)).toThrow(TypeError);
25
+ expect(() => asInt16(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
26
+ expect(() => asInt16(1.2)).toThrow(TypeError);
27
+ expect(() => asInt16(-3.4)).toThrow(TypeError);
28
+ });
29
+
30
+ test('returns the same value for valid inputs', () => {
31
+ expect(asInt16(5)).toBe(5);
32
+ expect(asInt16(-10)).toBe(-10);
33
+ expect(asInt16(0)).toBe(0);
34
+ expect(asInt16(32767)).toBe(32767);
35
+ expect(asInt16(-32768)).toBe(-32768);
36
+ });
37
+
38
+ test.each([
39
+ { name: 'Number.NaN', value: Number.NaN },
40
+ { name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
41
+ { name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
42
+ { name: '1.2', value: 1.2 },
43
+ { name: '-3.4', value: -3.4 },
44
+ ] as const)(`asInt16($name) should throw a TypeError`, ({ value }) => {
45
+ expect(() => asInt16(value)).toThrow(
46
+ new TypeError(`Expected an integer in [-2^15, 2^15), got: ${value}`),
47
+ );
48
+ });
49
+ });
50
+
51
+ describe('isInt16', () => {
52
+ test('correctly identifies int16 values', () => {
53
+ expect(isInt16(0)).toBe(true);
54
+ expect(isInt16(1)).toBe(true);
55
+ expect(isInt16(-1)).toBe(true);
56
+ expect(isInt16(32767)).toBe(true);
57
+ expect(isInt16(-32768)).toBe(true);
58
+ });
59
+
60
+ test('correctly identifies values outside int16 range', () => {
61
+ expect(isInt16(32768)).toBe(false);
62
+ expect(isInt16(-32769)).toBe(false);
63
+ expect(isInt16(65536)).toBe(false);
64
+ expect(isInt16(-65536)).toBe(false);
65
+ });
66
+
67
+ test('correctly identifies non-integers', () => {
68
+ expect(isInt16(Number.NaN)).toBe(false);
69
+ expect(isInt16(Number.POSITIVE_INFINITY)).toBe(false);
70
+ expect(isInt16(Number.NEGATIVE_INFINITY)).toBe(false);
71
+ expect(isInt16(1.2)).toBe(false);
72
+ expect(isInt16(-3.4)).toBe(false);
73
+ });
74
+ });
75
+
76
+ describe('Int16.is', () => {
77
+ test('same as isInt16 function', () => {
78
+ expect(Int16.is(5)).toBe(isInt16(5));
79
+ expect(Int16.is(32768)).toBe(isInt16(32768));
80
+ expect(Int16.is(-32769)).toBe(isInt16(-32769));
81
+ });
82
+ });
83
+
84
+ describe('constants', () => {
85
+ test('MIN_VALUE and MAX_VALUE', () => {
86
+ expect(Int16.MIN_VALUE).toBe(-32768);
87
+ expect(Int16.MAX_VALUE).toBe(32767);
88
+ });
89
+ });
90
+
91
+ describe('mathematical operations', () => {
92
+ const a = asInt16(100);
93
+ const b = asInt16(50);
94
+ const c = asInt16(-30);
95
+
96
+ test('abs', () => {
97
+ expect(Int16.abs(a)).toBe(100);
98
+ expect(Int16.abs(c)).toBe(30);
99
+ expect(Int16.abs(asInt16(0))).toBe(0);
100
+ });
101
+
102
+ test('min and max', () => {
103
+ expect(Int16.min(a, b)).toBe(50);
104
+ expect(Int16.max(a, b)).toBe(100);
105
+ expect(Int16.min(a, c)).toBe(-30);
106
+ expect(Int16.max(a, c)).toBe(100);
107
+ });
108
+
109
+ test('add (with clamping)', () => {
110
+ const result = Int16.add(asInt16(32000), asInt16(1000));
111
+ expect(result).toBe(32767); // clamped to max
112
+ expect(Int16.add(a, b)).toBe(150);
113
+ });
114
+
115
+ test('sub (with clamping)', () => {
116
+ const result = Int16.sub(asInt16(-32000), asInt16(1000));
117
+ expect(result).toBe(-32768); // clamped to min
118
+ expect(Int16.sub(a, b)).toBe(50);
119
+ });
120
+
121
+ test('mul (with clamping)', () => {
122
+ const result = Int16.mul(asInt16(1000), asInt16(100));
123
+ expect(result).toBe(32767); // clamped to max
124
+ expect(Int16.mul(asInt16(10), asInt16(5))).toBe(50);
125
+ });
126
+
127
+ test('div (floor division with clamping)', () => {
128
+ expect(Int16.div(a, asNonZeroInt16(50))).toBe(2);
129
+ expect(Int16.div(asInt16(7), asNonZeroInt16(3))).toBe(2);
130
+ expect(Int16.div(asInt16(-7), asNonZeroInt16(3))).toBe(-3);
131
+ });
132
+
133
+ test('pow (with clamping)', () => {
134
+ const result = Int16.pow(asInt16(200), asInt16(3));
135
+ expect(result).toBe(32767); // clamped to max
136
+ expect(Int16.pow(asInt16(2), asInt16(3))).toBe(8);
137
+ });
138
+ });
139
+
140
+ describe('random', () => {
141
+ test('generates int16 values within specified range', () => {
142
+ const min = -10;
143
+ const max = 10;
144
+
145
+ for (let i = 0; i < 10; i++) {
146
+ const result = Int16.random(min, max);
147
+ expect(result).toBeGreaterThanOrEqual(min);
148
+ expect(result).toBeLessThanOrEqual(max);
149
+ expect(Int16.is(result)).toBe(true);
150
+ expect(Number.isInteger(result)).toBe(true);
151
+ }
152
+ });
153
+
154
+ test('generates values within Int16 range', () => {
155
+ for (let i = 0; i < 10; i++) {
156
+ const result = Int16.random(-20, 20);
157
+ expect(result).toBeGreaterThanOrEqual(Int16.MIN_VALUE);
158
+ expect(result).toBeLessThanOrEqual(Int16.MAX_VALUE);
159
+ }
160
+ });
161
+ });
162
+
163
+ describe('type assertions', () => {
164
+ test('type relationships', () => {
165
+ expectType<Int16, number>('<=');
166
+
167
+ expectTypeOf(asInt16(100)).toExtend<Int16>();
168
+ });
169
+ });
170
+ });
@@ -0,0 +1,193 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { TsVerifiedInternals } from '../refined-number-utils.mjs';
3
+
4
+ type ElementType = Int32;
5
+
6
+ const typeNameInMessage = 'an integer in [-2^31, 2^31)';
7
+
8
+ const {
9
+ MIN_VALUE,
10
+ MAX_VALUE,
11
+ min: min_,
12
+ max: max_,
13
+ abs,
14
+ pow,
15
+ add,
16
+ sub,
17
+ mul,
18
+ div,
19
+ random,
20
+ is,
21
+ castType,
22
+ clamp,
23
+ } = TsVerifiedInternals.RefinedNumberUtils.operatorsForInteger<
24
+ ElementType,
25
+ number,
26
+ number
27
+ >({
28
+ integerOrSafeInteger: 'SafeInteger',
29
+ MIN_VALUE: -(2 ** 31),
30
+ MAX_VALUE: 2 ** 31 - 1,
31
+ typeNameInMessage,
32
+ } as const);
33
+
34
+ /**
35
+ * Checks if a number is an Int32 (32-bit signed integer in the range [-2^31, 2^31)).
36
+ * @param value The value to check.
37
+ * @returns `true` if the value is an Int32, `false` otherwise.
38
+ */
39
+ export const isInt32 = is;
40
+
41
+ /**
42
+ * Casts a number to an Int32 type.
43
+ * @param value The value to cast.
44
+ * @returns The value as an Int32 type.
45
+ * @throws {TypeError} If the value is not an integer in [-2^31, 2^31).
46
+ * @example
47
+ * ```typescript
48
+ * const x = asInt32(100000); // Int32
49
+ * const y = asInt32(-500000); // Int32
50
+ * // asInt32(3000000000); // throws TypeError
51
+ * // asInt32(1.5); // throws TypeError
52
+ * ```
53
+ */
54
+ export const asInt32 = castType;
55
+
56
+ /**
57
+ * Namespace providing type-safe arithmetic operations for 32-bit signed integers.
58
+ *
59
+ * All operations automatically clamp results to the valid Int32 range [-2147483648, 2147483647].
60
+ * This ensures that all arithmetic maintains the 32-bit signed integer constraint, preventing overflow.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const a = asInt32(2000000000);
65
+ * const b = asInt32(500000000);
66
+ *
67
+ * // Arithmetic operations with automatic clamping
68
+ * const sum = Int32.add(a, b); // Int32 (2147483647 - clamped to MAX_VALUE)
69
+ * const diff = Int32.sub(a, b); // Int32 (1500000000)
70
+ * const product = Int32.mul(a, b); // Int32 (2147483647 - clamped due to overflow)
71
+ *
72
+ * // Range operations
73
+ * const clamped = Int32.clamp(5000000000); // Int32 (2147483647)
74
+ * const minimum = Int32.min(a, b); // Int32 (500000000)
75
+ * const maximum = Int32.max(a, b); // Int32 (2000000000)
76
+ *
77
+ * // Utility operations
78
+ * const absolute = Int32.abs(asInt32(-1000)); // Int32 (1000)
79
+ * const random = Int32.random(); // Int32 (random value in valid range)
80
+ * ```
81
+ */
82
+ export const Int32 = {
83
+ /**
84
+ * Type guard to check if a value is an Int32.
85
+ * @param value The value to check.
86
+ * @returns `true` if the value is a 32-bit signed integer, `false` otherwise.
87
+ */
88
+ is,
89
+
90
+ /**
91
+ * The minimum value for a 32-bit signed integer.
92
+ * @readonly
93
+ */
94
+ MIN_VALUE,
95
+
96
+ /**
97
+ * The maximum value for a 32-bit signed integer.
98
+ * @readonly
99
+ */
100
+ MAX_VALUE,
101
+
102
+ /**
103
+ * Returns the absolute value of a 32-bit signed integer.
104
+ * @param a The Int32 value.
105
+ * @returns The absolute value as an Int32, clamped to valid range.
106
+ */
107
+ abs,
108
+
109
+ /**
110
+ * Returns the smaller of two Int32 values.
111
+ * @param a The first Int32.
112
+ * @param b The second Int32.
113
+ * @returns The minimum value as an Int32.
114
+ */
115
+ min: min_,
116
+
117
+ /**
118
+ * Returns the larger of two Int32 values.
119
+ * @param a The first Int32.
120
+ * @param b The second Int32.
121
+ * @returns The maximum value as an Int32.
122
+ */
123
+ max: max_,
124
+
125
+ /**
126
+ * Clamps a number to the Int32 range.
127
+ * @param value The number to clamp.
128
+ * @returns The value clamped to [-2147483648, 2147483647] as an Int32.
129
+ */
130
+ clamp,
131
+
132
+ /**
133
+ * Generates a random Int32 value within the valid range.
134
+ * @returns A random Int32 between MIN_VALUE and MAX_VALUE.
135
+ */
136
+ random,
137
+
138
+ /**
139
+ * Raises an Int32 to the power of another Int32.
140
+ * @param a The base Int32.
141
+ * @param b The exponent Int32.
142
+ * @returns `a ** b` clamped to [-2147483648, 2147483647] as an Int32.
143
+ */
144
+ pow,
145
+
146
+ /**
147
+ * Adds two Int32 values.
148
+ * @param a The first Int32.
149
+ * @param b The second Int32.
150
+ * @returns `a + b` clamped to [-2147483648, 2147483647] as an Int32.
151
+ */
152
+ add,
153
+
154
+ /**
155
+ * Subtracts one Int32 from another.
156
+ * @param a The minuend Int32.
157
+ * @param b The subtrahend Int32.
158
+ * @returns `a - b` clamped to [-2147483648, 2147483647] as an Int32.
159
+ */
160
+ sub,
161
+
162
+ /**
163
+ * Multiplies two Int32 values.
164
+ * @param a The first Int32.
165
+ * @param b The second Int32.
166
+ * @returns `a * b` clamped to [-2147483648, 2147483647] as an Int32.
167
+ */
168
+ mul,
169
+
170
+ /**
171
+ * Divides one Int32 by another using floor division.
172
+ * @param a The dividend Int32.
173
+ * @param b The divisor Int32.
174
+ * @returns `⌊a / b⌋` clamped to [-2147483648, 2147483647] as an Int32.
175
+ */
176
+ div,
177
+ } as const;
178
+
179
+ expectType<
180
+ keyof typeof Int32,
181
+ keyof TsVerifiedInternals.RefinedNumberUtils.NumberClass<
182
+ ElementType,
183
+ 'int' | 'range'
184
+ >
185
+ >('=');
186
+
187
+ expectType<
188
+ typeof Int32,
189
+ TsVerifiedInternals.RefinedNumberUtils.NumberClass<
190
+ ElementType,
191
+ 'int' | 'range'
192
+ >
193
+ >('<=');
@@ -0,0 +1,170 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { asInt32, Int32, isInt32 } from './int32.mjs';
3
+ import { asNonZeroInt32 } from './non-zero-int32.mjs';
4
+
5
+ describe('Int32', () => {
6
+ describe('asInt32', () => {
7
+ test('accepts valid int32 values', () => {
8
+ expect(() => asInt32(0)).not.toThrow();
9
+ expect(() => asInt32(1)).not.toThrow();
10
+ expect(() => asInt32(-1)).not.toThrow();
11
+ expect(() => asInt32(2147483647)).not.toThrow(); // 2^31 - 1
12
+ expect(() => asInt32(-2147483648)).not.toThrow(); // -2^31
13
+ });
14
+
15
+ test('rejects values outside int32 range', () => {
16
+ expect(() => asInt32(2147483648)).toThrow(TypeError); // 2^31
17
+ expect(() => asInt32(-2147483649)).toThrow(TypeError); // -2^31 - 1
18
+ expect(() => asInt32(4294967296)).toThrow(TypeError);
19
+ expect(() => asInt32(-4294967296)).toThrow(TypeError);
20
+ });
21
+
22
+ test('rejects non-integers', () => {
23
+ expect(() => asInt32(Number.NaN)).toThrow(TypeError);
24
+ expect(() => asInt32(Number.POSITIVE_INFINITY)).toThrow(TypeError);
25
+ expect(() => asInt32(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
26
+ expect(() => asInt32(1.2)).toThrow(TypeError);
27
+ expect(() => asInt32(-3.4)).toThrow(TypeError);
28
+ });
29
+
30
+ test('returns the same value for valid inputs', () => {
31
+ expect(asInt32(5)).toBe(5);
32
+ expect(asInt32(-10)).toBe(-10);
33
+ expect(asInt32(0)).toBe(0);
34
+ expect(asInt32(2147483647)).toBe(2147483647);
35
+ expect(asInt32(-2147483648)).toBe(-2147483648);
36
+ });
37
+
38
+ test.each([
39
+ { name: 'Number.NaN', value: Number.NaN },
40
+ { name: 'Number.POSITIVE_INFINITY', value: Number.POSITIVE_INFINITY },
41
+ { name: 'Number.NEGATIVE_INFINITY', value: Number.NEGATIVE_INFINITY },
42
+ { name: '1.2', value: 1.2 },
43
+ { name: '-3.4', value: -3.4 },
44
+ ] as const)(`asInt32($name) should throw a TypeError`, ({ value }) => {
45
+ expect(() => asInt32(value)).toThrow(
46
+ new TypeError(`Expected an integer in [-2^31, 2^31), got: ${value}`),
47
+ );
48
+ });
49
+ });
50
+
51
+ describe('isInt32', () => {
52
+ test('correctly identifies int32 values', () => {
53
+ expect(isInt32(0)).toBe(true);
54
+ expect(isInt32(1)).toBe(true);
55
+ expect(isInt32(-1)).toBe(true);
56
+ expect(isInt32(2147483647)).toBe(true);
57
+ expect(isInt32(-2147483648)).toBe(true);
58
+ });
59
+
60
+ test('correctly identifies values outside int32 range', () => {
61
+ expect(isInt32(2147483648)).toBe(false);
62
+ expect(isInt32(-2147483649)).toBe(false);
63
+ expect(isInt32(4294967296)).toBe(false);
64
+ expect(isInt32(-4294967296)).toBe(false);
65
+ });
66
+
67
+ test('correctly identifies non-integers', () => {
68
+ expect(isInt32(Number.NaN)).toBe(false);
69
+ expect(isInt32(Number.POSITIVE_INFINITY)).toBe(false);
70
+ expect(isInt32(Number.NEGATIVE_INFINITY)).toBe(false);
71
+ expect(isInt32(1.2)).toBe(false);
72
+ expect(isInt32(-3.4)).toBe(false);
73
+ });
74
+ });
75
+
76
+ describe('Int32.is', () => {
77
+ test('same as isInt32 function', () => {
78
+ expect(Int32.is(5)).toBe(isInt32(5));
79
+ expect(Int32.is(2147483648)).toBe(isInt32(2147483648));
80
+ expect(Int32.is(-2147483649)).toBe(isInt32(-2147483649));
81
+ });
82
+ });
83
+
84
+ describe('constants', () => {
85
+ test('MIN_VALUE and MAX_VALUE', () => {
86
+ expect(Int32.MIN_VALUE).toBe(-2147483648);
87
+ expect(Int32.MAX_VALUE).toBe(2147483647);
88
+ });
89
+ });
90
+
91
+ describe('mathematical operations', () => {
92
+ const a = asInt32(1000000);
93
+ const b = asInt32(500000);
94
+ const c = asInt32(-300000);
95
+
96
+ test('abs', () => {
97
+ expect(Int32.abs(a)).toBe(1000000);
98
+ expect(Int32.abs(c)).toBe(300000);
99
+ expect(Int32.abs(asInt32(0))).toBe(0);
100
+ });
101
+
102
+ test('min and max', () => {
103
+ expect(Int32.min(a, b)).toBe(500000);
104
+ expect(Int32.max(a, b)).toBe(1000000);
105
+ expect(Int32.min(a, c)).toBe(-300000);
106
+ expect(Int32.max(a, c)).toBe(1000000);
107
+ });
108
+
109
+ test('add (with clamping)', () => {
110
+ const result = Int32.add(asInt32(2147483000), asInt32(1000));
111
+ expect(result).toBe(2147483647); // clamped to max
112
+ expect(Int32.add(a, b)).toBe(1500000);
113
+ });
114
+
115
+ test('sub (with clamping)', () => {
116
+ const result = Int32.sub(asInt32(-2147483000), asInt32(1000));
117
+ expect(result).toBe(-2147483648); // clamped to min
118
+ expect(Int32.sub(a, b)).toBe(500000);
119
+ });
120
+
121
+ test('mul (with clamping)', () => {
122
+ const result = Int32.mul(asInt32(100000), asInt32(100000));
123
+ expect(result).toBe(2147483647); // clamped to max
124
+ expect(Int32.mul(asInt32(1000), asInt32(5))).toBe(5000);
125
+ });
126
+
127
+ test('div (floor division with clamping)', () => {
128
+ expect(Int32.div(a, asNonZeroInt32(500000))).toBe(2);
129
+ expect(Int32.div(asInt32(7), asNonZeroInt32(3))).toBe(2);
130
+ expect(Int32.div(asInt32(-7), asNonZeroInt32(3))).toBe(-3);
131
+ });
132
+
133
+ test('pow (with clamping)', () => {
134
+ const result = Int32.pow(asInt32(10000), asInt32(3));
135
+ expect(result).toBe(2147483647); // clamped to max
136
+ expect(Int32.pow(asInt32(2), asInt32(3))).toBe(8);
137
+ });
138
+ });
139
+
140
+ describe('random', () => {
141
+ test('generates int32 values within specified range', () => {
142
+ const min = -10;
143
+ const max = 10;
144
+
145
+ for (let i = 0; i < 10; i++) {
146
+ const result = Int32.random(min, max);
147
+ expect(result).toBeGreaterThanOrEqual(min);
148
+ expect(result).toBeLessThanOrEqual(max);
149
+ expect(Int32.is(result)).toBe(true);
150
+ expect(Number.isInteger(result)).toBe(true);
151
+ }
152
+ });
153
+
154
+ test('generates values within Int32 range', () => {
155
+ for (let i = 0; i < 10; i++) {
156
+ const result = Int32.random(-20, 20);
157
+ expect(result).toBeGreaterThanOrEqual(Int32.MIN_VALUE);
158
+ expect(result).toBeLessThanOrEqual(Int32.MAX_VALUE);
159
+ }
160
+ });
161
+ });
162
+
163
+ describe('type assertions', () => {
164
+ test('type relationships', () => {
165
+ expectType<Int32, number>('<=');
166
+
167
+ expectTypeOf(asInt32(1000000)).toExtend<Int32>();
168
+ });
169
+ });
170
+ });