ts-data-forge 6.13.0 → 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 (181) 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/functional/pipe.d.mts +6 -18
  33. package/dist/functional/pipe.d.mts.map +1 -1
  34. package/dist/functional/pipe.mjs +35 -15
  35. package/dist/functional/pipe.mjs.map +1 -1
  36. package/dist/index.mjs +6 -0
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/iterator/range.mjs +6 -0
  39. package/dist/iterator/range.mjs.map +1 -1
  40. package/dist/json/json.mjs +6 -0
  41. package/dist/json/json.mjs.map +1 -1
  42. package/dist/number/branded-types/finite-number.d.mts +1 -1
  43. package/dist/number/branded-types/index.d.mts +6 -0
  44. package/dist/number/branded-types/index.d.mts.map +1 -1
  45. package/dist/number/branded-types/index.mjs +6 -0
  46. package/dist/number/branded-types/index.mjs.map +1 -1
  47. package/dist/number/branded-types/int.d.mts +1 -2
  48. package/dist/number/branded-types/int.d.mts.map +1 -1
  49. package/dist/number/branded-types/int16.d.mts +2 -3
  50. package/dist/number/branded-types/int16.d.mts.map +1 -1
  51. package/dist/number/branded-types/int32.d.mts +2 -3
  52. package/dist/number/branded-types/int32.d.mts.map +1 -1
  53. package/dist/number/branded-types/negative-finite-number.d.mts +143 -0
  54. package/dist/number/branded-types/negative-finite-number.d.mts.map +1 -0
  55. package/dist/number/branded-types/negative-finite-number.mjs +156 -0
  56. package/dist/number/branded-types/negative-finite-number.mjs.map +1 -0
  57. package/dist/number/branded-types/negative-int.d.mts +120 -0
  58. package/dist/number/branded-types/negative-int.d.mts.map +1 -0
  59. package/dist/number/branded-types/negative-int.mjs +125 -0
  60. package/dist/number/branded-types/negative-int.mjs.map +1 -0
  61. package/dist/number/branded-types/negative-safe-int.d.mts +132 -0
  62. package/dist/number/branded-types/negative-safe-int.d.mts.map +1 -0
  63. package/dist/number/branded-types/negative-safe-int.mjs +136 -0
  64. package/dist/number/branded-types/negative-safe-int.mjs.map +1 -0
  65. package/dist/number/branded-types/non-negative-finite-number.d.mts +1 -1
  66. package/dist/number/branded-types/non-negative-int16.d.mts +1 -1
  67. package/dist/number/branded-types/non-negative-int32.d.mts +1 -1
  68. package/dist/number/branded-types/non-positive-finite-number.d.mts +130 -0
  69. package/dist/number/branded-types/non-positive-finite-number.d.mts.map +1 -0
  70. package/dist/number/branded-types/non-positive-finite-number.mjs +134 -0
  71. package/dist/number/branded-types/non-positive-finite-number.mjs.map +1 -0
  72. package/dist/number/branded-types/non-positive-int.d.mts +224 -0
  73. package/dist/number/branded-types/non-positive-int.d.mts.map +1 -0
  74. package/dist/number/branded-types/non-positive-int.mjs +222 -0
  75. package/dist/number/branded-types/non-positive-int.mjs.map +1 -0
  76. package/dist/number/branded-types/non-positive-safe-int.d.mts +119 -0
  77. package/dist/number/branded-types/non-positive-safe-int.d.mts.map +1 -0
  78. package/dist/number/branded-types/non-positive-safe-int.mjs +116 -0
  79. package/dist/number/branded-types/non-positive-safe-int.mjs.map +1 -0
  80. package/dist/number/branded-types/non-zero-finite-number.d.mts +5 -17
  81. package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -1
  82. package/dist/number/branded-types/non-zero-finite-number.mjs +5 -17
  83. package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -1
  84. package/dist/number/branded-types/non-zero-int.d.mts +5 -33
  85. package/dist/number/branded-types/non-zero-int.d.mts.map +1 -1
  86. package/dist/number/branded-types/non-zero-int.mjs +5 -25
  87. package/dist/number/branded-types/non-zero-int.mjs.map +1 -1
  88. package/dist/number/branded-types/non-zero-int16.d.mts +6 -43
  89. package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -1
  90. package/dist/number/branded-types/non-zero-int16.mjs +5 -25
  91. package/dist/number/branded-types/non-zero-int16.mjs.map +1 -1
  92. package/dist/number/branded-types/non-zero-int32.d.mts +6 -39
  93. package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -1
  94. package/dist/number/branded-types/non-zero-int32.mjs +5 -25
  95. package/dist/number/branded-types/non-zero-int32.mjs.map +1 -1
  96. package/dist/number/branded-types/non-zero-safe-int.d.mts +5 -37
  97. package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -1
  98. package/dist/number/branded-types/non-zero-safe-int.mjs +5 -28
  99. package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -1
  100. package/dist/number/branded-types/non-zero-uint16.d.mts +6 -33
  101. package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -1
  102. package/dist/number/branded-types/non-zero-uint16.mjs +5 -17
  103. package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -1
  104. package/dist/number/branded-types/non-zero-uint32.d.mts +6 -31
  105. package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -1
  106. package/dist/number/branded-types/non-zero-uint32.mjs +5 -17
  107. package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -1
  108. package/dist/number/branded-types/positive-finite-number.d.mts +4 -2
  109. package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -1
  110. package/dist/number/branded-types/positive-int.d.mts +4 -2
  111. package/dist/number/branded-types/positive-int.d.mts.map +1 -1
  112. package/dist/number/branded-types/positive-int16.d.mts +4 -2
  113. package/dist/number/branded-types/positive-int16.d.mts.map +1 -1
  114. package/dist/number/branded-types/positive-int32.d.mts +4 -2
  115. package/dist/number/branded-types/positive-int32.d.mts.map +1 -1
  116. package/dist/number/branded-types/positive-safe-int.d.mts +4 -2
  117. package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -1
  118. package/dist/number/branded-types/positive-uint16.d.mts +4 -2
  119. package/dist/number/branded-types/positive-uint16.d.mts.map +1 -1
  120. package/dist/number/branded-types/positive-uint32.d.mts +4 -2
  121. package/dist/number/branded-types/positive-uint32.d.mts.map +1 -1
  122. package/dist/number/branded-types/safe-int.d.mts +1 -2
  123. package/dist/number/branded-types/safe-int.d.mts.map +1 -1
  124. package/dist/number/branded-types/safe-uint.d.mts +1 -1
  125. package/dist/number/branded-types/uint.d.mts +1 -1
  126. package/dist/number/branded-types/uint16.d.mts +1 -1
  127. package/dist/number/branded-types/uint32.d.mts +1 -1
  128. package/dist/number/index.d.mts +1 -0
  129. package/dist/number/index.d.mts.map +1 -1
  130. package/dist/number/index.mjs +6 -0
  131. package/dist/number/index.mjs.map +1 -1
  132. package/dist/number/num-arithmetic-types.d.mts +74 -0
  133. package/dist/number/num-arithmetic-types.d.mts.map +1 -0
  134. package/dist/number/num-arithmetic-types.mjs +2 -0
  135. package/dist/number/num-arithmetic-types.mjs.map +1 -0
  136. package/dist/number/num.d.mts +53 -9
  137. package/dist/number/num.d.mts.map +1 -1
  138. package/dist/number/num.mjs +64 -12
  139. package/dist/number/num.mjs.map +1 -1
  140. package/dist/number/refined-number-utils.d.mts +12 -9
  141. package/dist/number/refined-number-utils.d.mts.map +1 -1
  142. package/dist/number/refined-number-utils.mjs.map +1 -1
  143. package/dist/object/object.mjs +6 -0
  144. package/dist/object/object.mjs.map +1 -1
  145. package/package.json +5 -2
  146. package/src/functional/pipe.mts +104 -78
  147. package/src/functional/pipe.test.mts +57 -1
  148. package/src/number/branded-types/index.mts +6 -0
  149. package/src/number/branded-types/negative-finite-number.mts +210 -0
  150. package/src/number/branded-types/negative-finite-number.test.mts +172 -0
  151. package/src/number/branded-types/negative-int.mts +160 -0
  152. package/src/number/branded-types/negative-int.test.mts +146 -0
  153. package/src/number/branded-types/negative-safe-int.mts +173 -0
  154. package/src/number/branded-types/negative-safe-int.test.mts +120 -0
  155. package/src/number/branded-types/non-positive-finite-number.mts +191 -0
  156. package/src/number/branded-types/non-positive-finite-number.test.mts +286 -0
  157. package/src/number/branded-types/non-positive-int.mts +251 -0
  158. package/src/number/branded-types/non-positive-int.test.mts +197 -0
  159. package/src/number/branded-types/non-positive-safe-int.mts +147 -0
  160. package/src/number/branded-types/non-positive-safe-int.test.mts +223 -0
  161. package/src/number/branded-types/non-zero-finite-number.mts +14 -22
  162. package/src/number/branded-types/non-zero-finite-number.test.mts +0 -12
  163. package/src/number/branded-types/non-zero-int.mts +10 -32
  164. package/src/number/branded-types/non-zero-int.test.mts +0 -20
  165. package/src/number/branded-types/non-zero-int16.mts +8 -32
  166. package/src/number/branded-types/non-zero-int16.test.mts +0 -30
  167. package/src/number/branded-types/non-zero-int32.mts +8 -32
  168. package/src/number/branded-types/non-zero-int32.test.mts +0 -30
  169. package/src/number/branded-types/non-zero-safe-int.mts +8 -35
  170. package/src/number/branded-types/non-zero-safe-int.test.mts +0 -32
  171. package/src/number/branded-types/non-zero-uint16.mts +8 -22
  172. package/src/number/branded-types/non-zero-uint16.test.mts +0 -16
  173. package/src/number/branded-types/non-zero-uint32.mts +8 -22
  174. package/src/number/branded-types/non-zero-uint32.test.mts +0 -16
  175. package/src/number/index.mts +1 -0
  176. package/src/number/num-arithmetic-types.mts +269 -0
  177. package/src/number/num-arithmetic-types.test.mts +130 -0
  178. package/src/number/num-arithmetic.test.mts +102 -0
  179. package/src/number/num.mts +96 -15
  180. package/src/number/refined-number-utils.mts +19 -9
  181. package/src/others/map-nullable.test.mts +3 -4
@@ -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;
@@ -0,0 +1,223 @@
1
+ import { expectType } from '../../expect-type.mjs';
2
+ import { range } from '../../iterator/index.mjs';
3
+ import {
4
+ asNonPositiveSafeInt,
5
+ isNonPositiveSafeInt,
6
+ NonPositiveSafeInt,
7
+ } from './non-positive-safe-int.mjs';
8
+
9
+ describe('NonPositiveSafeInt test', () => {
10
+ describe(asNonPositiveSafeInt, () => {
11
+ test('accepts valid non-positive safe integer values', () => {
12
+ expect(() => asNonPositiveSafeInt(0)).not.toThrow();
13
+
14
+ expect(() => asNonPositiveSafeInt(-1)).not.toThrow();
15
+
16
+ expect(() => asNonPositiveSafeInt(-1000)).not.toThrow();
17
+
18
+ expect(() => asNonPositiveSafeInt(Number.MIN_SAFE_INTEGER)).not.toThrow();
19
+ });
20
+
21
+ test('rejects positive integers', () => {
22
+ expect(() => asNonPositiveSafeInt(1)).toThrow(TypeError);
23
+
24
+ expect(() => asNonPositiveSafeInt(42)).toThrow(TypeError);
25
+
26
+ expect(() => asNonPositiveSafeInt(Number.MAX_SAFE_INTEGER)).toThrow(
27
+ TypeError,
28
+ );
29
+ });
30
+
31
+ test('rejects values outside safe integer range', () => {
32
+ expect(() => asNonPositiveSafeInt(Number.MIN_SAFE_INTEGER - 1)).toThrow(
33
+ TypeError,
34
+ );
35
+
36
+ expect(() => asNonPositiveSafeInt(Number.MAX_SAFE_INTEGER + 1)).toThrow(
37
+ TypeError,
38
+ );
39
+ });
40
+
41
+ test('rejects non-integers', () => {
42
+ expect(() => asNonPositiveSafeInt(Number.NaN)).toThrow(TypeError);
43
+
44
+ expect(() => asNonPositiveSafeInt(Number.POSITIVE_INFINITY)).toThrow(
45
+ TypeError,
46
+ );
47
+
48
+ expect(() => asNonPositiveSafeInt(Number.NEGATIVE_INFINITY)).toThrow(
49
+ TypeError,
50
+ );
51
+
52
+ expect(() => asNonPositiveSafeInt(-1.2)).toThrow(TypeError);
53
+
54
+ expect(() => asNonPositiveSafeInt(3.4)).toThrow(TypeError);
55
+ });
56
+
57
+ test('returns the same value for valid inputs', () => {
58
+ expect(asNonPositiveSafeInt(0)).toBe(0);
59
+
60
+ expect(asNonPositiveSafeInt(-5)).toBe(-5);
61
+
62
+ expect(asNonPositiveSafeInt(Number.MIN_SAFE_INTEGER)).toBe(
63
+ Number.MIN_SAFE_INTEGER,
64
+ );
65
+ });
66
+
67
+ test('throws TypeError for invalid values', () => {
68
+ expect(() => asNonPositiveSafeInt(1)).toThrow(TypeError);
69
+
70
+ expect(() => asNonPositiveSafeInt(Number.MIN_SAFE_INTEGER - 1)).toThrow(
71
+ TypeError,
72
+ );
73
+
74
+ expect(() => asNonPositiveSafeInt(Number.NaN)).toThrow(TypeError);
75
+ });
76
+ });
77
+
78
+ describe(isNonPositiveSafeInt, () => {
79
+ test('correctly identifies non-positive safe integers', () => {
80
+ assert.isTrue(isNonPositiveSafeInt(0));
81
+
82
+ assert.isTrue(isNonPositiveSafeInt(-1));
83
+
84
+ assert.isTrue(isNonPositiveSafeInt(-1000));
85
+
86
+ assert.isTrue(isNonPositiveSafeInt(Number.MIN_SAFE_INTEGER));
87
+ });
88
+
89
+ test('correctly identifies positive integers', () => {
90
+ assert.isFalse(isNonPositiveSafeInt(1));
91
+
92
+ assert.isFalse(isNonPositiveSafeInt(42));
93
+
94
+ assert.isFalse(isNonPositiveSafeInt(Number.MAX_SAFE_INTEGER));
95
+ });
96
+
97
+ test('correctly identifies values outside safe integer range', () => {
98
+ assert.isFalse(isNonPositiveSafeInt(Number.MIN_SAFE_INTEGER - 1));
99
+
100
+ assert.isFalse(isNonPositiveSafeInt(Number.MAX_SAFE_INTEGER + 1));
101
+ });
102
+
103
+ test('correctly identifies non-integers', () => {
104
+ assert.isFalse(isNonPositiveSafeInt(Number.NaN));
105
+
106
+ assert.isFalse(isNonPositiveSafeInt(Number.POSITIVE_INFINITY));
107
+
108
+ assert.isFalse(isNonPositiveSafeInt(Number.NEGATIVE_INFINITY));
109
+
110
+ assert.isFalse(isNonPositiveSafeInt(-1.2));
111
+
112
+ assert.isFalse(isNonPositiveSafeInt(3.4));
113
+ });
114
+ });
115
+
116
+ describe('NonPositiveSafeInt.is', () => {
117
+ test('works as a type guard', () => {
118
+ const value: number = -42;
119
+
120
+ if (NonPositiveSafeInt.is(value)) {
121
+ expectType<typeof value, typeof value & NonPositiveSafeInt>('=');
122
+ }
123
+ });
124
+ });
125
+
126
+ describe('NonPositiveSafeInt.MIN_VALUE', () => {
127
+ test('is Number.MIN_SAFE_INTEGER', () => {
128
+ expect(NonPositiveSafeInt.MIN_VALUE).toBe(Number.MIN_SAFE_INTEGER);
129
+ });
130
+ });
131
+
132
+ describe('NonPositiveSafeInt.MAX_VALUE', () => {
133
+ test('is 0', () => {
134
+ expect(NonPositiveSafeInt.MAX_VALUE).toBe(0);
135
+ });
136
+ });
137
+
138
+ describe('NonPositiveSafeInt.min', () => {
139
+ test('returns the smaller value', () => {
140
+ expect(NonPositiveSafeInt.min(-5, -10)).toBe(-10);
141
+
142
+ expect(NonPositiveSafeInt.min(0, -1)).toBe(-1);
143
+ });
144
+
145
+ test('clamps to range when necessary', () => {
146
+ expect(NonPositiveSafeInt.min(-5, 10)).toBe(-5);
147
+
148
+ expect(NonPositiveSafeInt.min(5, 10)).toBe(0);
149
+ });
150
+ });
151
+
152
+ describe('NonPositiveSafeInt.max', () => {
153
+ test('returns the larger value', () => {
154
+ expect(NonPositiveSafeInt.max(-5, -10)).toBe(-5);
155
+
156
+ expect(NonPositiveSafeInt.max(-1, 0)).toBe(0);
157
+ });
158
+
159
+ test('clamps to range when necessary', () => {
160
+ expect(NonPositiveSafeInt.max(-5, -10)).toBe(-5);
161
+
162
+ expect(NonPositiveSafeInt.max(-5, 10)).toBe(0);
163
+ });
164
+ });
165
+
166
+ describe('NonPositiveSafeInt.clamp', () => {
167
+ test('returns the same value if within range', () => {
168
+ expect(NonPositiveSafeInt.clamp(-5)).toBe(-5);
169
+
170
+ expect(NonPositiveSafeInt.clamp(0)).toBe(0);
171
+
172
+ expect(NonPositiveSafeInt.clamp(-1000)).toBe(-1000);
173
+ });
174
+
175
+ test('clamps positive values to MAX_VALUE (0)', () => {
176
+ expect(NonPositiveSafeInt.clamp(5)).toBe(0);
177
+
178
+ expect(NonPositiveSafeInt.clamp(1000)).toBe(0);
179
+ });
180
+
181
+ test('clamps out-of-range negative values to MIN_VALUE', () => {
182
+ expect(NonPositiveSafeInt.clamp(Number.MIN_SAFE_INTEGER - 1)).toBe(
183
+ Number.MIN_SAFE_INTEGER,
184
+ );
185
+ });
186
+ });
187
+
188
+ describe('NonPositiveSafeInt.add', () => {
189
+ test('adds two non-positive integers', () => {
190
+ expect(NonPositiveSafeInt.add(-5, -3)).toBe(-8);
191
+
192
+ expect(NonPositiveSafeInt.add(0, -10)).toBe(-10);
193
+ });
194
+
195
+ test('clamps result to MAX_VALUE (0) when sum is positive', () => {
196
+ expect(NonPositiveSafeInt.add(-5, 10)).toBe(0);
197
+
198
+ expect(NonPositiveSafeInt.add(0, 0)).toBe(0);
199
+ });
200
+ });
201
+
202
+ describe('NonPositiveSafeInt.sub', () => {
203
+ test('subtracts two non-positive integers', () => {
204
+ expect(NonPositiveSafeInt.sub(-10, -3)).toBe(-7);
205
+
206
+ expect(NonPositiveSafeInt.sub(0, -5)).toBe(0);
207
+ });
208
+
209
+ test('clamps result to MAX_VALUE (0) when result is positive', () => {
210
+ expect(NonPositiveSafeInt.sub(-5, -10)).toBe(0);
211
+ });
212
+ });
213
+
214
+ describe('NonPositiveSafeInt.random', () => {
215
+ test('generates values within range', () => {
216
+ for (const _ of range(100)) {
217
+ const value = NonPositiveSafeInt.random();
218
+
219
+ assert.isTrue(isNonPositiveSafeInt(value));
220
+ }
221
+ });
222
+ });
223
+ });
@@ -15,7 +15,6 @@ const typeNameInMessage = 'a non-zero finite number';
15
15
 
16
16
  const {
17
17
  abs,
18
- add,
19
18
  castType,
20
19
  div,
21
20
  is,
@@ -24,7 +23,6 @@ const {
24
23
  mul,
25
24
  pow,
26
25
  randomNonZero: random,
27
- sub,
28
26
  } = TsDataForgeInternals.RefinedNumberUtils.operatorsForFloat<
29
27
  ElementType,
30
28
  number,
@@ -169,24 +167,6 @@ export const NonZeroFiniteNumber = {
169
167
  */
170
168
  pow,
171
169
 
172
- /**
173
- * Adds two NonZeroFiniteNumber values.
174
- *
175
- * @param a The first NonZeroFiniteNumber.
176
- * @param b The second NonZeroFiniteNumber.
177
- * @returns `a + b` as a NonZeroFiniteNumber.
178
- */
179
- add,
180
-
181
- /**
182
- * Subtracts one NonZeroFiniteNumber from another.
183
- *
184
- * @param a The minuend NonZeroFiniteNumber.
185
- * @param b The subtrahend NonZeroFiniteNumber.
186
- * @returns `a - b` as a NonZeroFiniteNumber.
187
- */
188
- sub,
189
-
190
170
  /**
191
171
  * Multiplies two NonZeroFiniteNumber values.
192
172
  *
@@ -199,6 +179,10 @@ export const NonZeroFiniteNumber = {
199
179
  /**
200
180
  * Divides one NonZeroFiniteNumber by another.
201
181
  *
182
+ * Exact (non-flooring) division of two non-zero finite numbers is always
183
+ * non-zero, so this stays closed. For the non-closed operations (`add`/`sub`,
184
+ * whose result may be `0`) use {@link Num.add}/{@link Num.sub}.
185
+ *
202
186
  * @param a The dividend NonZeroFiniteNumber.
203
187
  * @param b The divisor NonZeroFiniteNumber.
204
188
  * @returns `a / b` as a NonZeroFiniteNumber.
@@ -213,10 +197,18 @@ expectType<
213
197
 
214
198
  expectType<
215
199
  keyof typeof NonZeroFiniteNumber,
216
- keyof TsDataForgeInternals.RefinedNumberUtils.NumberClass<ElementType, never>
200
+ keyof TsDataForgeInternals.RefinedNumberUtils.NumberClass<
201
+ ElementType,
202
+ never,
203
+ 'div' | 'mul'
204
+ >
217
205
  >('=');
218
206
 
219
207
  expectType<
220
208
  typeof NonZeroFiniteNumber,
221
- TsDataForgeInternals.RefinedNumberUtils.NumberClass<ElementType, never>
209
+ TsDataForgeInternals.RefinedNumberUtils.NumberClass<
210
+ ElementType,
211
+ never,
212
+ 'div' | 'mul'
213
+ >
222
214
  >('<=');
@@ -146,18 +146,6 @@ describe('NonZeroFiniteNumber test', () => {
146
146
  expect(NonZeroFiniteNumber.round(c)).toBe(-3);
147
147
  });
148
148
 
149
- test('add', () => {
150
- expect(NonZeroFiniteNumber.add(a, b)).toBe(8);
151
-
152
- expect(NonZeroFiniteNumber.add(a, c)).toBe(2);
153
- });
154
-
155
- test('sub', () => {
156
- expect(NonZeroFiniteNumber.sub(a, b)).toBe(3);
157
-
158
- expect(NonZeroFiniteNumber.sub(a, c)).toBe(9);
159
- });
160
-
161
149
  test('mul', () => {
162
150
  expect(NonZeroFiniteNumber.mul(a, b)).toBe(13.75);
163
151