ts-data-forge 6.13.1 → 7.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 (174) hide show
  1. package/README.md +2 -2
  2. package/dist/array/impl/array-utils-iterators.mjs +6 -0
  3. package/dist/array/impl/array-utils-iterators.mjs.map +1 -1
  4. package/dist/array/impl/array-utils-modification.mjs +6 -0
  5. package/dist/array/impl/array-utils-modification.mjs.map +1 -1
  6. package/dist/array/impl/array-utils-reducing-value.mjs +6 -0
  7. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  8. package/dist/array/impl/array-utils-search.mjs +6 -0
  9. package/dist/array/impl/array-utils-search.mjs.map +1 -1
  10. package/dist/array/impl/array-utils-slice-clamped.mjs +6 -0
  11. package/dist/array/impl/array-utils-slice-clamped.mjs.map +1 -1
  12. package/dist/array/impl/array-utils-slicing.mjs +6 -0
  13. package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
  14. package/dist/array/impl/array-utils-transformation.mjs +6 -0
  15. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  16. package/dist/array/impl/array-utils-validation.mjs +6 -0
  17. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  18. package/dist/collections/imap-mapped.mjs +6 -0
  19. package/dist/collections/imap-mapped.mjs.map +1 -1
  20. package/dist/collections/imap.mjs +6 -0
  21. package/dist/collections/imap.mjs.map +1 -1
  22. package/dist/collections/iset-mapped.mjs +6 -0
  23. package/dist/collections/iset-mapped.mjs.map +1 -1
  24. package/dist/collections/iset.mjs +6 -0
  25. package/dist/collections/iset.mjs.map +1 -1
  26. package/dist/collections/queue.mjs +6 -0
  27. package/dist/collections/queue.mjs.map +1 -1
  28. package/dist/collections/stack.mjs +6 -0
  29. package/dist/collections/stack.mjs.map +1 -1
  30. package/dist/entry-point.mjs +6 -0
  31. package/dist/entry-point.mjs.map +1 -1
  32. package/dist/index.mjs +6 -0
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/iterator/range.mjs +6 -0
  35. package/dist/iterator/range.mjs.map +1 -1
  36. package/dist/json/json.mjs +6 -0
  37. package/dist/json/json.mjs.map +1 -1
  38. package/dist/number/branded-types/finite-number.d.mts +1 -1
  39. package/dist/number/branded-types/index.d.mts +6 -0
  40. package/dist/number/branded-types/index.d.mts.map +1 -1
  41. package/dist/number/branded-types/index.mjs +6 -0
  42. package/dist/number/branded-types/index.mjs.map +1 -1
  43. package/dist/number/branded-types/int.d.mts +1 -2
  44. package/dist/number/branded-types/int.d.mts.map +1 -1
  45. package/dist/number/branded-types/int16.d.mts +2 -3
  46. package/dist/number/branded-types/int16.d.mts.map +1 -1
  47. package/dist/number/branded-types/int32.d.mts +2 -3
  48. package/dist/number/branded-types/int32.d.mts.map +1 -1
  49. package/dist/number/branded-types/negative-finite-number.d.mts +143 -0
  50. package/dist/number/branded-types/negative-finite-number.d.mts.map +1 -0
  51. package/dist/number/branded-types/negative-finite-number.mjs +156 -0
  52. package/dist/number/branded-types/negative-finite-number.mjs.map +1 -0
  53. package/dist/number/branded-types/negative-int.d.mts +120 -0
  54. package/dist/number/branded-types/negative-int.d.mts.map +1 -0
  55. package/dist/number/branded-types/negative-int.mjs +125 -0
  56. package/dist/number/branded-types/negative-int.mjs.map +1 -0
  57. package/dist/number/branded-types/negative-safe-int.d.mts +132 -0
  58. package/dist/number/branded-types/negative-safe-int.d.mts.map +1 -0
  59. package/dist/number/branded-types/negative-safe-int.mjs +136 -0
  60. package/dist/number/branded-types/negative-safe-int.mjs.map +1 -0
  61. package/dist/number/branded-types/non-negative-finite-number.d.mts +1 -1
  62. package/dist/number/branded-types/non-negative-int16.d.mts +1 -1
  63. package/dist/number/branded-types/non-negative-int32.d.mts +1 -1
  64. package/dist/number/branded-types/non-positive-finite-number.d.mts +130 -0
  65. package/dist/number/branded-types/non-positive-finite-number.d.mts.map +1 -0
  66. package/dist/number/branded-types/non-positive-finite-number.mjs +134 -0
  67. package/dist/number/branded-types/non-positive-finite-number.mjs.map +1 -0
  68. package/dist/number/branded-types/non-positive-int.d.mts +224 -0
  69. package/dist/number/branded-types/non-positive-int.d.mts.map +1 -0
  70. package/dist/number/branded-types/non-positive-int.mjs +222 -0
  71. package/dist/number/branded-types/non-positive-int.mjs.map +1 -0
  72. package/dist/number/branded-types/non-positive-safe-int.d.mts +119 -0
  73. package/dist/number/branded-types/non-positive-safe-int.d.mts.map +1 -0
  74. package/dist/number/branded-types/non-positive-safe-int.mjs +116 -0
  75. package/dist/number/branded-types/non-positive-safe-int.mjs.map +1 -0
  76. package/dist/number/branded-types/non-zero-finite-number.d.mts +5 -17
  77. package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -1
  78. package/dist/number/branded-types/non-zero-finite-number.mjs +5 -17
  79. package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -1
  80. package/dist/number/branded-types/non-zero-int.d.mts +5 -33
  81. package/dist/number/branded-types/non-zero-int.d.mts.map +1 -1
  82. package/dist/number/branded-types/non-zero-int.mjs +5 -25
  83. package/dist/number/branded-types/non-zero-int.mjs.map +1 -1
  84. package/dist/number/branded-types/non-zero-int16.d.mts +6 -43
  85. package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -1
  86. package/dist/number/branded-types/non-zero-int16.mjs +5 -25
  87. package/dist/number/branded-types/non-zero-int16.mjs.map +1 -1
  88. package/dist/number/branded-types/non-zero-int32.d.mts +6 -39
  89. package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -1
  90. package/dist/number/branded-types/non-zero-int32.mjs +5 -25
  91. package/dist/number/branded-types/non-zero-int32.mjs.map +1 -1
  92. package/dist/number/branded-types/non-zero-safe-int.d.mts +5 -37
  93. package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -1
  94. package/dist/number/branded-types/non-zero-safe-int.mjs +5 -28
  95. package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -1
  96. package/dist/number/branded-types/non-zero-uint16.d.mts +6 -33
  97. package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -1
  98. package/dist/number/branded-types/non-zero-uint16.mjs +5 -17
  99. package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -1
  100. package/dist/number/branded-types/non-zero-uint32.d.mts +6 -31
  101. package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -1
  102. package/dist/number/branded-types/non-zero-uint32.mjs +5 -17
  103. package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -1
  104. package/dist/number/branded-types/positive-finite-number.d.mts +4 -2
  105. package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -1
  106. package/dist/number/branded-types/positive-int.d.mts +4 -2
  107. package/dist/number/branded-types/positive-int.d.mts.map +1 -1
  108. package/dist/number/branded-types/positive-int16.d.mts +4 -2
  109. package/dist/number/branded-types/positive-int16.d.mts.map +1 -1
  110. package/dist/number/branded-types/positive-int32.d.mts +4 -2
  111. package/dist/number/branded-types/positive-int32.d.mts.map +1 -1
  112. package/dist/number/branded-types/positive-safe-int.d.mts +4 -2
  113. package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -1
  114. package/dist/number/branded-types/positive-uint16.d.mts +4 -2
  115. package/dist/number/branded-types/positive-uint16.d.mts.map +1 -1
  116. package/dist/number/branded-types/positive-uint32.d.mts +4 -2
  117. package/dist/number/branded-types/positive-uint32.d.mts.map +1 -1
  118. package/dist/number/branded-types/safe-int.d.mts +1 -2
  119. package/dist/number/branded-types/safe-int.d.mts.map +1 -1
  120. package/dist/number/branded-types/safe-uint.d.mts +1 -1
  121. package/dist/number/branded-types/uint.d.mts +1 -1
  122. package/dist/number/branded-types/uint16.d.mts +1 -1
  123. package/dist/number/branded-types/uint32.d.mts +1 -1
  124. package/dist/number/index.d.mts +1 -0
  125. package/dist/number/index.d.mts.map +1 -1
  126. package/dist/number/index.mjs +6 -0
  127. package/dist/number/index.mjs.map +1 -1
  128. package/dist/number/num-arithmetic-types.d.mts +74 -0
  129. package/dist/number/num-arithmetic-types.d.mts.map +1 -0
  130. package/dist/number/num-arithmetic-types.mjs +2 -0
  131. package/dist/number/num-arithmetic-types.mjs.map +1 -0
  132. package/dist/number/num.d.mts +53 -9
  133. package/dist/number/num.d.mts.map +1 -1
  134. package/dist/number/num.mjs +64 -12
  135. package/dist/number/num.mjs.map +1 -1
  136. package/dist/number/refined-number-utils.d.mts +12 -9
  137. package/dist/number/refined-number-utils.d.mts.map +1 -1
  138. package/dist/number/refined-number-utils.mjs.map +1 -1
  139. package/dist/object/object.mjs +6 -0
  140. package/dist/object/object.mjs.map +1 -1
  141. package/package.json +2 -2
  142. package/src/number/branded-types/index.mts +6 -0
  143. package/src/number/branded-types/negative-finite-number.mts +210 -0
  144. package/src/number/branded-types/negative-finite-number.test.mts +172 -0
  145. package/src/number/branded-types/negative-int.mts +160 -0
  146. package/src/number/branded-types/negative-int.test.mts +146 -0
  147. package/src/number/branded-types/negative-safe-int.mts +173 -0
  148. package/src/number/branded-types/negative-safe-int.test.mts +120 -0
  149. package/src/number/branded-types/non-positive-finite-number.mts +191 -0
  150. package/src/number/branded-types/non-positive-finite-number.test.mts +286 -0
  151. package/src/number/branded-types/non-positive-int.mts +251 -0
  152. package/src/number/branded-types/non-positive-int.test.mts +197 -0
  153. package/src/number/branded-types/non-positive-safe-int.mts +147 -0
  154. package/src/number/branded-types/non-positive-safe-int.test.mts +223 -0
  155. package/src/number/branded-types/non-zero-finite-number.mts +14 -22
  156. package/src/number/branded-types/non-zero-finite-number.test.mts +0 -12
  157. package/src/number/branded-types/non-zero-int.mts +10 -32
  158. package/src/number/branded-types/non-zero-int.test.mts +0 -20
  159. package/src/number/branded-types/non-zero-int16.mts +8 -32
  160. package/src/number/branded-types/non-zero-int16.test.mts +0 -30
  161. package/src/number/branded-types/non-zero-int32.mts +8 -32
  162. package/src/number/branded-types/non-zero-int32.test.mts +0 -30
  163. package/src/number/branded-types/non-zero-safe-int.mts +8 -35
  164. package/src/number/branded-types/non-zero-safe-int.test.mts +0 -32
  165. package/src/number/branded-types/non-zero-uint16.mts +8 -22
  166. package/src/number/branded-types/non-zero-uint16.test.mts +0 -16
  167. package/src/number/branded-types/non-zero-uint32.mts +8 -22
  168. package/src/number/branded-types/non-zero-uint32.test.mts +0 -16
  169. package/src/number/index.mts +1 -0
  170. package/src/number/num-arithmetic-types.mts +269 -0
  171. package/src/number/num-arithmetic-types.test.mts +130 -0
  172. package/src/number/num-arithmetic.test.mts +102 -0
  173. package/src/number/num.mts +96 -15
  174. package/src/number/refined-number-utils.mts +19 -9
@@ -0,0 +1,251 @@
1
+ import { type NonPositiveInt as TtfImported_NonPositiveInt } from 'ts-type-forge';
2
+ import { TsDataForgeInternals } from '../refined-number-utils.mjs';
3
+
4
+ export type NonPositiveInt = TtfImported_NonPositiveInt;
5
+
6
+ type ElementType = NonPositiveInt;
7
+
8
+ const typeNameInMessage = 'a non-positive integer';
9
+
10
+ const {
11
+ MAX_VALUE,
12
+ add,
13
+ castType,
14
+ clamp,
15
+ is,
16
+ max: max_,
17
+ min: min_,
18
+ pow,
19
+ random,
20
+ sub,
21
+ } = TsDataForgeInternals.RefinedNumberUtils.operatorsForInteger<
22
+ ElementType,
23
+ number,
24
+ 0
25
+ >({
26
+ integerOrSafeInteger: 'Integer',
27
+ MIN_VALUE: -Number.MAX_VALUE,
28
+ MAX_VALUE: 0,
29
+ typeNameInMessage,
30
+ } as const);
31
+
32
+ /**
33
+ * Type guard that checks if a value is a non-positive integer.
34
+ *
35
+ * A non-positive integer is any integer less than or equal to zero (<= 0).
36
+ * This includes zero and all negative integers, but excludes positive numbers
37
+ * and non-integers.
38
+ *
39
+ * @example
40
+ *
41
+ * ```ts
42
+ * assert.isTrue(isNonPositiveInt(0));
43
+ *
44
+ * assert.isTrue(isNonPositiveInt(-5));
45
+ *
46
+ * assert.isFalse(isNonPositiveInt(1));
47
+ * ```
48
+ *
49
+ * @param value - The value to check
50
+ * @returns `true` if the value is a non-positive integer, `false` otherwise
51
+ */
52
+ export const isNonPositiveInt = is;
53
+
54
+ /**
55
+ * Casts a number to a NonPositiveInt branded type.
56
+ *
57
+ * This function validates that the input is a non-positive integer (<= 0) and
58
+ * returns it with the NonPositiveInt brand. This ensures type safety for
59
+ * operations that require non-positive integer values.
60
+ *
61
+ * @example
62
+ *
63
+ * ```ts
64
+ * const branded = asNonPositiveInt(-7);
65
+ *
66
+ * assert.isTrue(branded === -7);
67
+ *
68
+ * assert.isTrue(NonPositiveInt.is(branded));
69
+ * ```
70
+ *
71
+ * @param value - The value to cast
72
+ * @returns The value as a NonPositiveInt branded type
73
+ * @throws {TypeError} If the value is not a non-positive integer
74
+ */
75
+ export const asNonPositiveInt = castType;
76
+
77
+ /**
78
+ * Namespace providing type-safe operations for NonPositiveInt branded types.
79
+ *
80
+ * NonPositiveInt represents integers that are less than or equal to zero (<= 0).
81
+ * All operations automatically clamp results to maintain the non-positive
82
+ * constraint, ensuring that arithmetic operations never produce positive values.
83
+ *
84
+ * This type is essential for:
85
+ *
86
+ * - Debts and negative balances
87
+ * - Penalties and reductions
88
+ * - Offsets and adjustments (downward)
89
+ * - Negative counts or differences
90
+ * - Depth or altitude below a reference point
91
+ */
92
+ export const NonPositiveInt = {
93
+ /**
94
+ * Type guard that checks if a value is a non-positive integer.
95
+ *
96
+ * @example
97
+ *
98
+ * ```ts
99
+ * const value: number = -42;
100
+ *
101
+ * if (NonPositiveInt.is(value)) {
102
+ * // value is now typed as NonPositiveInt
103
+ * const debt = value;
104
+ * }
105
+ * ```
106
+ *
107
+ * @param value - The value to check
108
+ * @returns `true` if the value is a non-positive integer, `false` otherwise
109
+ */
110
+ is,
111
+
112
+ /**
113
+ * The maximum value for a non-positive integer.
114
+ *
115
+ * @readonly
116
+ */
117
+ MAX_VALUE,
118
+
119
+ /**
120
+ * Returns the smaller of two non-positive integers.
121
+ *
122
+ * Since non-positive integers range from negative infinity to 0, the smaller
123
+ * value is the one further from zero (more negative).
124
+ *
125
+ * @example
126
+ *
127
+ * ```ts
128
+ * const result = NonPositiveInt.min(-5, -10);
129
+ *
130
+ * assert.strictEqual(result, -10);
131
+ * ```
132
+ *
133
+ * @param a - The first non-positive integer
134
+ * @param b - The second non-positive integer
135
+ * @returns The minimum value as a non-positive integer
136
+ */
137
+ min: min_,
138
+
139
+ /**
140
+ * Returns the larger of two non-positive integers.
141
+ *
142
+ * Since non-positive integers range from negative infinity to 0, the larger
143
+ * value is the one closer to zero (less negative).
144
+ *
145
+ * @example
146
+ *
147
+ * ```ts
148
+ * const result = NonPositiveInt.max(-5, -10);
149
+ *
150
+ * assert.strictEqual(result, -5);
151
+ * ```
152
+ *
153
+ * @param a - The first non-positive integer
154
+ * @param b - The second non-positive integer
155
+ * @returns The maximum value as a non-positive integer
156
+ */
157
+ max: max_,
158
+
159
+ /**
160
+ * Clamps a number to the non-positive integer range.
161
+ *
162
+ * Any positive value is clamped to 0 (the maximum non-positive integer).
163
+ * Negative values are preserved as long as they are valid integers.
164
+ *
165
+ * @example
166
+ *
167
+ * ```ts
168
+ * assert.strictEqual(NonPositiveInt.clamp(5), 0);
169
+ *
170
+ * assert.strictEqual(NonPositiveInt.clamp(-5), -5);
171
+ *
172
+ * assert.strictEqual(NonPositiveInt.clamp(0), 0);
173
+ * ```
174
+ *
175
+ * @param value - The number to clamp
176
+ * @returns The value clamped to the non-positive integer range
177
+ */
178
+ clamp,
179
+
180
+ /**
181
+ * Generates a random non-positive integer value.
182
+ *
183
+ * @example
184
+ *
185
+ * ```ts
186
+ * const randomValue = NonPositiveInt.random();
187
+ *
188
+ * assert.isTrue(NonPositiveInt.is(randomValue));
189
+ * ```
190
+ *
191
+ * @returns A random non-positive integer
192
+ */
193
+ random,
194
+
195
+ /**
196
+ * Raises a non-positive integer to the power of another non-positive integer.
197
+ *
198
+ * The result is clamped to the non-positive integer range.
199
+ *
200
+ * @example
201
+ *
202
+ * ```ts
203
+ * const result = NonPositiveInt.pow(-2, -1);
204
+ * ```
205
+ *
206
+ * @param a - The base non-positive integer
207
+ * @param b - The exponent non-positive integer
208
+ * @returns `a ** b` clamped to the non-positive integer range
209
+ */
210
+ pow,
211
+
212
+ /**
213
+ * Adds two non-positive integers.
214
+ *
215
+ * The result is clamped to the non-positive integer range. If the sum is
216
+ * positive, it is clamped to 0.
217
+ *
218
+ * @example
219
+ *
220
+ * ```ts
221
+ * assert.strictEqual(NonPositiveInt.add(-5, -3), -8);
222
+ *
223
+ * assert.strictEqual(NonPositiveInt.add(-5, 10), 0);
224
+ * ```
225
+ *
226
+ * @param a - The first non-positive integer
227
+ * @param b - The second non-positive integer
228
+ * @returns `a + b` clamped to the non-positive integer range
229
+ */
230
+ add,
231
+
232
+ /**
233
+ * Subtracts one non-positive integer from another.
234
+ *
235
+ * The result is clamped to the non-positive integer range. If the result is
236
+ * positive, it is clamped to 0.
237
+ *
238
+ * @example
239
+ *
240
+ * ```ts
241
+ * assert.strictEqual(NonPositiveInt.sub(-10, -3), -7);
242
+ *
243
+ * assert.strictEqual(NonPositiveInt.sub(-10, 5), 0);
244
+ * ```
245
+ *
246
+ * @param a - The minuend non-positive integer
247
+ * @param b - The subtrahend non-positive integer
248
+ * @returns `a - b` clamped to the non-positive integer range
249
+ */
250
+ sub,
251
+ } as const;
@@ -0,0 +1,197 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
3
+ import {
4
+ asNonPositiveInt,
5
+ isNonPositiveInt,
6
+ NonPositiveInt,
7
+ } from './non-positive-int.mjs';
8
+
9
+ describe('NonPositiveInt test', () => {
10
+ describe(asNonPositiveInt, () => {
11
+ test('accepts valid non-positive integers', () => {
12
+ expect(() => asNonPositiveInt(0)).not.toThrow();
13
+
14
+ expect(() => asNonPositiveInt(-1)).not.toThrow();
15
+
16
+ expect(() => asNonPositiveInt(-1000)).not.toThrow();
17
+
18
+ expect(() => asNonPositiveInt(Number.MIN_SAFE_INTEGER)).not.toThrow();
19
+ });
20
+
21
+ test('rejects positive integers', () => {
22
+ expect(() => asNonPositiveInt(1)).toThrow(TypeError);
23
+
24
+ expect(() => asNonPositiveInt(42)).toThrow(TypeError);
25
+
26
+ expect(() => asNonPositiveInt(Number.MAX_SAFE_INTEGER)).toThrow(
27
+ TypeError,
28
+ );
29
+ });
30
+
31
+ test('rejects non-integers', () => {
32
+ expect(() => asNonPositiveInt(Number.NaN)).toThrow(TypeError);
33
+
34
+ expect(() => asNonPositiveInt(Number.POSITIVE_INFINITY)).toThrow(
35
+ TypeError,
36
+ );
37
+
38
+ expect(() => asNonPositiveInt(Number.NEGATIVE_INFINITY)).toThrow(
39
+ TypeError,
40
+ );
41
+
42
+ expect(() => asNonPositiveInt(-1.5)).toThrow(TypeError);
43
+
44
+ expect(() => asNonPositiveInt(3.7)).toThrow(TypeError);
45
+ });
46
+
47
+ test('returns the same value for valid inputs', () => {
48
+ expect(asNonPositiveInt(0)).toBe(0);
49
+
50
+ expect(asNonPositiveInt(-5)).toBe(-5);
51
+
52
+ expect(asNonPositiveInt(Number.MIN_SAFE_INTEGER)).toBe(
53
+ Number.MIN_SAFE_INTEGER,
54
+ );
55
+ });
56
+ });
57
+
58
+ describe(isNonPositiveInt, () => {
59
+ test('correctly identifies non-positive integers', () => {
60
+ assert.isTrue(isNonPositiveInt(0));
61
+
62
+ assert.isTrue(isNonPositiveInt(-1));
63
+
64
+ assert.isTrue(isNonPositiveInt(-1000));
65
+
66
+ assert.isTrue(isNonPositiveInt(Number.MIN_SAFE_INTEGER));
67
+ });
68
+
69
+ test('correctly rejects positive integers', () => {
70
+ assert.isFalse(isNonPositiveInt(1));
71
+
72
+ assert.isFalse(isNonPositiveInt(42));
73
+
74
+ assert.isFalse(isNonPositiveInt(Number.MAX_SAFE_INTEGER));
75
+ });
76
+
77
+ test('correctly rejects non-integers', () => {
78
+ assert.isFalse(isNonPositiveInt(Number.NaN));
79
+
80
+ assert.isFalse(isNonPositiveInt(Number.POSITIVE_INFINITY));
81
+
82
+ assert.isFalse(isNonPositiveInt(Number.NEGATIVE_INFINITY));
83
+
84
+ assert.isFalse(isNonPositiveInt(-1.5));
85
+
86
+ assert.isFalse(isNonPositiveInt(3.7));
87
+ });
88
+ });
89
+
90
+ describe('NonPositiveInt.is', () => {
91
+ test('works as a type guard', () => {
92
+ const value: number = -42;
93
+
94
+ if (NonPositiveInt.is(value)) {
95
+ expectType<typeof value, typeof value & NonPositiveInt>('=');
96
+ }
97
+ });
98
+ });
99
+
100
+ describe('NonPositiveInt.MAX_VALUE', () => {
101
+ test('is 0', () => {
102
+ expect(NonPositiveInt.MAX_VALUE).toBe(0);
103
+ });
104
+ });
105
+
106
+ describe('NonPositiveInt.min', () => {
107
+ test('returns the smaller value', () => {
108
+ expect(NonPositiveInt.min(-5, -10)).toBe(-10);
109
+
110
+ expect(NonPositiveInt.min(0, -1)).toBe(-1);
111
+ });
112
+
113
+ test('clamps to range when necessary', () => {
114
+ expect(NonPositiveInt.min(-5, 10)).toBe(-5);
115
+
116
+ expect(NonPositiveInt.min(5, 10)).toBe(0);
117
+ });
118
+ });
119
+
120
+ describe('NonPositiveInt.max', () => {
121
+ test('returns the larger value', () => {
122
+ expect(NonPositiveInt.max(-5, -10)).toBe(-5);
123
+
124
+ expect(NonPositiveInt.max(-1, 0)).toBe(0);
125
+ });
126
+
127
+ test('clamps to range when necessary', () => {
128
+ expect(NonPositiveInt.max(-5, -10)).toBe(-5);
129
+
130
+ expect(NonPositiveInt.max(-5, 10)).toBe(0);
131
+ });
132
+ });
133
+
134
+ describe('NonPositiveInt.clamp', () => {
135
+ test('returns the same value if within range', () => {
136
+ expect(NonPositiveInt.clamp(-5)).toBe(-5);
137
+
138
+ expect(NonPositiveInt.clamp(0)).toBe(0);
139
+
140
+ expect(NonPositiveInt.clamp(-1000)).toBe(-1000);
141
+ });
142
+
143
+ test('clamps positive values to MAX_VALUE (0)', () => {
144
+ expect(NonPositiveInt.clamp(5)).toBe(0);
145
+
146
+ expect(NonPositiveInt.clamp(1000)).toBe(0);
147
+ });
148
+
149
+ test('clamps -Infinity to the lower bound', () => {
150
+ expect(NonPositiveInt.clamp(Number.NEGATIVE_INFINITY)).toBe(
151
+ -Number.MAX_VALUE,
152
+ );
153
+ });
154
+ });
155
+
156
+ describe('NonPositiveInt.add', () => {
157
+ test('adds two non-positive integers', () => {
158
+ expect(NonPositiveInt.add(-5, -3)).toBe(-8);
159
+
160
+ expect(NonPositiveInt.add(0, -10)).toBe(-10);
161
+ });
162
+
163
+ test('clamps result to MAX_VALUE (0) when sum is positive', () => {
164
+ expect(NonPositiveInt.add(-5, 10)).toBe(0);
165
+
166
+ expect(NonPositiveInt.add(0, 0)).toBe(0);
167
+ });
168
+ });
169
+
170
+ describe('NonPositiveInt.sub', () => {
171
+ test('subtracts two non-positive integers', () => {
172
+ expect(NonPositiveInt.sub(-10, -3)).toBe(-7);
173
+
174
+ expect(NonPositiveInt.sub(0, -5)).toBe(0);
175
+ });
176
+
177
+ test('clamps result to MAX_VALUE (0) when result is positive', () => {
178
+ expect(NonPositiveInt.sub(-5, -10)).toBe(0);
179
+ });
180
+ });
181
+
182
+ describe('NonPositiveInt.pow', () => {
183
+ test('raises to power', () => {
184
+ expect(NonPositiveInt.pow(-2, -1)).toBeDefined();
185
+ });
186
+ });
187
+
188
+ describe('NonPositiveInt.random', () => {
189
+ test('generates values within range', () => {
190
+ for (const _ of range(100)) {
191
+ const value = NonPositiveInt.random();
192
+
193
+ assert.isTrue(isNonPositiveInt(value));
194
+ }
195
+ });
196
+ });
197
+ });
@@ -0,0 +1,147 @@
1
+ import { type NonPositiveSafeInt as TtfImported_NonPositiveSafeInt } from 'ts-type-forge';
2
+ import { TsDataForgeInternals } from '../refined-number-utils.mjs';
3
+
4
+ export type NonPositiveSafeInt = TtfImported_NonPositiveSafeInt;
5
+
6
+ type ElementType = NonPositiveSafeInt;
7
+
8
+ const typeNameInMessage = 'a non-positive safe integer';
9
+
10
+ const {
11
+ MAX_VALUE,
12
+ MIN_VALUE,
13
+ add,
14
+ castType,
15
+ clamp,
16
+ is,
17
+ max: max_,
18
+ min: min_,
19
+ pow,
20
+ random,
21
+ sub,
22
+ } = TsDataForgeInternals.RefinedNumberUtils.operatorsForInteger<
23
+ ElementType,
24
+ number,
25
+ 0
26
+ >({
27
+ integerOrSafeInteger: 'SafeInteger',
28
+ MIN_VALUE: Number.MIN_SAFE_INTEGER,
29
+ MAX_VALUE: 0,
30
+ typeNameInMessage,
31
+ } as const);
32
+
33
+ /**
34
+ * Checks if a number is a NonPositiveSafeInt (non-positive safe integer in the
35
+ * range [Number.MIN_SAFE_INTEGER, 0]).
36
+ *
37
+ * @param value The value to check.
38
+ * @returns `true` if the value is a NonPositiveSafeInt, `false` otherwise.
39
+ */
40
+ export const isNonPositiveSafeInt = is;
41
+
42
+ /**
43
+ * Casts a number to a NonPositiveSafeInt type.
44
+ *
45
+ * @param value The value to cast.
46
+ * @returns The value as a NonPositiveSafeInt type.
47
+ * @throws {TypeError} If the value is not a non-positive safe integer.
48
+ */
49
+ export const asNonPositiveSafeInt = castType;
50
+
51
+ /**
52
+ * Namespace providing type-safe arithmetic operations for non-positive
53
+ * safe integers.
54
+ *
55
+ * All operations automatically clamp results to the valid NonPositiveSafeInt
56
+ * range [Number.MIN_SAFE_INTEGER, 0]. This ensures that all arithmetic
57
+ * maintains the non-positive safe integer constraint, with positive results
58
+ * clamped to 0 and underflow results clamped to MIN_VALUE.
59
+ */
60
+ export const NonPositiveSafeInt = {
61
+ /**
62
+ * Type guard to check if a value is a NonPositiveSafeInt.
63
+ *
64
+ * @param value The value to check.
65
+ * @returns `true` if the value is a non-positive safe integer, `false`
66
+ * otherwise.
67
+ */
68
+ is,
69
+
70
+ /**
71
+ * The minimum value for a non-positive safe integer.
72
+ *
73
+ * @readonly
74
+ */
75
+ MIN_VALUE,
76
+
77
+ /**
78
+ * The maximum value for a non-positive safe integer.
79
+ *
80
+ * @readonly
81
+ */
82
+ MAX_VALUE,
83
+
84
+ /**
85
+ * Returns the smaller of two NonPositiveSafeInt values.
86
+ *
87
+ * @param a The first NonPositiveSafeInt.
88
+ * @param b The second NonPositiveSafeInt.
89
+ * @returns The minimum value as a NonPositiveSafeInt.
90
+ */
91
+ min: min_,
92
+
93
+ /**
94
+ * Returns the larger of two NonPositiveSafeInt values.
95
+ *
96
+ * @param a The first NonPositiveSafeInt.
97
+ * @param b The second NonPositiveSafeInt.
98
+ * @returns The maximum value as a NonPositiveSafeInt.
99
+ */
100
+ max: max_,
101
+
102
+ /**
103
+ * Clamps a number to the NonPositiveSafeInt range.
104
+ *
105
+ * @param value The number to clamp.
106
+ * @returns The value clamped to [Number.MIN_SAFE_INTEGER, 0] as a
107
+ * NonPositiveSafeInt.
108
+ */
109
+ clamp,
110
+
111
+ /**
112
+ * Generates a random NonPositiveSafeInt value within the valid range.
113
+ *
114
+ * @returns A random NonPositiveSafeInt between Number.MIN_SAFE_INTEGER and 0.
115
+ */
116
+ random,
117
+
118
+ /**
119
+ * Raises a NonPositiveSafeInt to the power of another NonPositiveSafeInt.
120
+ *
121
+ * @param a The base NonPositiveSafeInt.
122
+ * @param b The exponent NonPositiveSafeInt.
123
+ * @returns `a ** b` clamped to [Number.MIN_SAFE_INTEGER, 0] as a
124
+ * NonPositiveSafeInt.
125
+ */
126
+ pow,
127
+
128
+ /**
129
+ * Adds two NonPositiveSafeInt values.
130
+ *
131
+ * @param a The first NonPositiveSafeInt.
132
+ * @param b The second NonPositiveSafeInt.
133
+ * @returns `a + b` clamped to [Number.MIN_SAFE_INTEGER, 0] as a
134
+ * NonPositiveSafeInt.
135
+ */
136
+ add,
137
+
138
+ /**
139
+ * Subtracts one NonPositiveSafeInt from another.
140
+ *
141
+ * @param a The minuend NonPositiveSafeInt.
142
+ * @param b The subtrahend NonPositiveSafeInt.
143
+ * @returns `a - b` clamped to [Number.MIN_SAFE_INTEGER, 0] as a
144
+ * NonPositiveSafeInt (maximum 0).
145
+ */
146
+ sub,
147
+ } as const;