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.
- package/README.md +2 -2
- package/dist/array/impl/array-utils-iterators.mjs +6 -0
- package/dist/array/impl/array-utils-iterators.mjs.map +1 -1
- package/dist/array/impl/array-utils-modification.mjs +6 -0
- package/dist/array/impl/array-utils-modification.mjs.map +1 -1
- package/dist/array/impl/array-utils-reducing-value.mjs +6 -0
- package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
- package/dist/array/impl/array-utils-search.mjs +6 -0
- package/dist/array/impl/array-utils-search.mjs.map +1 -1
- package/dist/array/impl/array-utils-slice-clamped.mjs +6 -0
- package/dist/array/impl/array-utils-slice-clamped.mjs.map +1 -1
- package/dist/array/impl/array-utils-slicing.mjs +6 -0
- package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
- package/dist/array/impl/array-utils-transformation.mjs +6 -0
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
- package/dist/array/impl/array-utils-validation.mjs +6 -0
- package/dist/array/impl/array-utils-validation.mjs.map +1 -1
- package/dist/collections/imap-mapped.mjs +6 -0
- package/dist/collections/imap-mapped.mjs.map +1 -1
- package/dist/collections/imap.mjs +6 -0
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.mjs +6 -0
- package/dist/collections/iset-mapped.mjs.map +1 -1
- package/dist/collections/iset.mjs +6 -0
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/collections/queue.mjs +6 -0
- package/dist/collections/queue.mjs.map +1 -1
- package/dist/collections/stack.mjs +6 -0
- package/dist/collections/stack.mjs.map +1 -1
- package/dist/entry-point.mjs +6 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/functional/pipe.d.mts +6 -18
- package/dist/functional/pipe.d.mts.map +1 -1
- package/dist/functional/pipe.mjs +35 -15
- package/dist/functional/pipe.mjs.map +1 -1
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -1
- package/dist/iterator/range.mjs +6 -0
- package/dist/iterator/range.mjs.map +1 -1
- package/dist/json/json.mjs +6 -0
- package/dist/json/json.mjs.map +1 -1
- package/dist/number/branded-types/finite-number.d.mts +1 -1
- package/dist/number/branded-types/index.d.mts +6 -0
- package/dist/number/branded-types/index.d.mts.map +1 -1
- package/dist/number/branded-types/index.mjs +6 -0
- package/dist/number/branded-types/index.mjs.map +1 -1
- package/dist/number/branded-types/int.d.mts +1 -2
- package/dist/number/branded-types/int.d.mts.map +1 -1
- package/dist/number/branded-types/int16.d.mts +2 -3
- package/dist/number/branded-types/int16.d.mts.map +1 -1
- package/dist/number/branded-types/int32.d.mts +2 -3
- package/dist/number/branded-types/int32.d.mts.map +1 -1
- package/dist/number/branded-types/negative-finite-number.d.mts +143 -0
- package/dist/number/branded-types/negative-finite-number.d.mts.map +1 -0
- package/dist/number/branded-types/negative-finite-number.mjs +156 -0
- package/dist/number/branded-types/negative-finite-number.mjs.map +1 -0
- package/dist/number/branded-types/negative-int.d.mts +120 -0
- package/dist/number/branded-types/negative-int.d.mts.map +1 -0
- package/dist/number/branded-types/negative-int.mjs +125 -0
- package/dist/number/branded-types/negative-int.mjs.map +1 -0
- package/dist/number/branded-types/negative-safe-int.d.mts +132 -0
- package/dist/number/branded-types/negative-safe-int.d.mts.map +1 -0
- package/dist/number/branded-types/negative-safe-int.mjs +136 -0
- package/dist/number/branded-types/negative-safe-int.mjs.map +1 -0
- package/dist/number/branded-types/non-negative-finite-number.d.mts +1 -1
- package/dist/number/branded-types/non-negative-int16.d.mts +1 -1
- package/dist/number/branded-types/non-negative-int32.d.mts +1 -1
- package/dist/number/branded-types/non-positive-finite-number.d.mts +130 -0
- package/dist/number/branded-types/non-positive-finite-number.d.mts.map +1 -0
- package/dist/number/branded-types/non-positive-finite-number.mjs +134 -0
- package/dist/number/branded-types/non-positive-finite-number.mjs.map +1 -0
- package/dist/number/branded-types/non-positive-int.d.mts +224 -0
- package/dist/number/branded-types/non-positive-int.d.mts.map +1 -0
- package/dist/number/branded-types/non-positive-int.mjs +222 -0
- package/dist/number/branded-types/non-positive-int.mjs.map +1 -0
- package/dist/number/branded-types/non-positive-safe-int.d.mts +119 -0
- package/dist/number/branded-types/non-positive-safe-int.d.mts.map +1 -0
- package/dist/number/branded-types/non-positive-safe-int.mjs +116 -0
- package/dist/number/branded-types/non-positive-safe-int.mjs.map +1 -0
- package/dist/number/branded-types/non-zero-finite-number.d.mts +5 -17
- package/dist/number/branded-types/non-zero-finite-number.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-finite-number.mjs +5 -17
- package/dist/number/branded-types/non-zero-finite-number.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-int.d.mts +5 -33
- package/dist/number/branded-types/non-zero-int.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-int.mjs +5 -25
- package/dist/number/branded-types/non-zero-int.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-int16.d.mts +6 -43
- package/dist/number/branded-types/non-zero-int16.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-int16.mjs +5 -25
- package/dist/number/branded-types/non-zero-int16.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-int32.d.mts +6 -39
- package/dist/number/branded-types/non-zero-int32.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-int32.mjs +5 -25
- package/dist/number/branded-types/non-zero-int32.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-safe-int.d.mts +5 -37
- package/dist/number/branded-types/non-zero-safe-int.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-safe-int.mjs +5 -28
- package/dist/number/branded-types/non-zero-safe-int.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-uint16.d.mts +6 -33
- package/dist/number/branded-types/non-zero-uint16.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-uint16.mjs +5 -17
- package/dist/number/branded-types/non-zero-uint16.mjs.map +1 -1
- package/dist/number/branded-types/non-zero-uint32.d.mts +6 -31
- package/dist/number/branded-types/non-zero-uint32.d.mts.map +1 -1
- package/dist/number/branded-types/non-zero-uint32.mjs +5 -17
- package/dist/number/branded-types/non-zero-uint32.mjs.map +1 -1
- package/dist/number/branded-types/positive-finite-number.d.mts +4 -2
- package/dist/number/branded-types/positive-finite-number.d.mts.map +1 -1
- package/dist/number/branded-types/positive-int.d.mts +4 -2
- package/dist/number/branded-types/positive-int.d.mts.map +1 -1
- package/dist/number/branded-types/positive-int16.d.mts +4 -2
- package/dist/number/branded-types/positive-int16.d.mts.map +1 -1
- package/dist/number/branded-types/positive-int32.d.mts +4 -2
- package/dist/number/branded-types/positive-int32.d.mts.map +1 -1
- package/dist/number/branded-types/positive-safe-int.d.mts +4 -2
- package/dist/number/branded-types/positive-safe-int.d.mts.map +1 -1
- package/dist/number/branded-types/positive-uint16.d.mts +4 -2
- package/dist/number/branded-types/positive-uint16.d.mts.map +1 -1
- package/dist/number/branded-types/positive-uint32.d.mts +4 -2
- package/dist/number/branded-types/positive-uint32.d.mts.map +1 -1
- package/dist/number/branded-types/safe-int.d.mts +1 -2
- package/dist/number/branded-types/safe-int.d.mts.map +1 -1
- package/dist/number/branded-types/safe-uint.d.mts +1 -1
- package/dist/number/branded-types/uint.d.mts +1 -1
- package/dist/number/branded-types/uint16.d.mts +1 -1
- package/dist/number/branded-types/uint32.d.mts +1 -1
- package/dist/number/index.d.mts +1 -0
- package/dist/number/index.d.mts.map +1 -1
- package/dist/number/index.mjs +6 -0
- package/dist/number/index.mjs.map +1 -1
- package/dist/number/num-arithmetic-types.d.mts +74 -0
- package/dist/number/num-arithmetic-types.d.mts.map +1 -0
- package/dist/number/num-arithmetic-types.mjs +2 -0
- package/dist/number/num-arithmetic-types.mjs.map +1 -0
- package/dist/number/num.d.mts +53 -9
- package/dist/number/num.d.mts.map +1 -1
- package/dist/number/num.mjs +64 -12
- package/dist/number/num.mjs.map +1 -1
- package/dist/number/refined-number-utils.d.mts +12 -9
- package/dist/number/refined-number-utils.d.mts.map +1 -1
- package/dist/number/refined-number-utils.mjs.map +1 -1
- package/dist/object/object.mjs +6 -0
- package/dist/object/object.mjs.map +1 -1
- package/package.json +5 -2
- package/src/functional/pipe.mts +104 -78
- package/src/functional/pipe.test.mts +57 -1
- package/src/number/branded-types/index.mts +6 -0
- package/src/number/branded-types/negative-finite-number.mts +210 -0
- package/src/number/branded-types/negative-finite-number.test.mts +172 -0
- package/src/number/branded-types/negative-int.mts +160 -0
- package/src/number/branded-types/negative-int.test.mts +146 -0
- package/src/number/branded-types/negative-safe-int.mts +173 -0
- package/src/number/branded-types/negative-safe-int.test.mts +120 -0
- package/src/number/branded-types/non-positive-finite-number.mts +191 -0
- package/src/number/branded-types/non-positive-finite-number.test.mts +286 -0
- package/src/number/branded-types/non-positive-int.mts +251 -0
- package/src/number/branded-types/non-positive-int.test.mts +197 -0
- package/src/number/branded-types/non-positive-safe-int.mts +147 -0
- package/src/number/branded-types/non-positive-safe-int.test.mts +223 -0
- package/src/number/branded-types/non-zero-finite-number.mts +14 -22
- package/src/number/branded-types/non-zero-finite-number.test.mts +0 -12
- package/src/number/branded-types/non-zero-int.mts +10 -32
- package/src/number/branded-types/non-zero-int.test.mts +0 -20
- package/src/number/branded-types/non-zero-int16.mts +8 -32
- package/src/number/branded-types/non-zero-int16.test.mts +0 -30
- package/src/number/branded-types/non-zero-int32.mts +8 -32
- package/src/number/branded-types/non-zero-int32.test.mts +0 -30
- package/src/number/branded-types/non-zero-safe-int.mts +8 -35
- package/src/number/branded-types/non-zero-safe-int.test.mts +0 -32
- package/src/number/branded-types/non-zero-uint16.mts +8 -22
- package/src/number/branded-types/non-zero-uint16.test.mts +0 -16
- package/src/number/branded-types/non-zero-uint32.mts +8 -22
- package/src/number/branded-types/non-zero-uint32.test.mts +0 -16
- package/src/number/index.mts +1 -0
- package/src/number/num-arithmetic-types.mts +269 -0
- package/src/number/num-arithmetic-types.test.mts +130 -0
- package/src/number/num-arithmetic.test.mts +102 -0
- package/src/number/num.mts +96 -15
- package/src/number/refined-number-utils.mts +19 -9
- package/src/others/map-nullable.test.mts +3 -4
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { type PositiveInt } from 'ts-type-forge';
|
|
2
|
+
import { expectType } from '../../expect-type.mjs';
|
|
3
|
+
import { range } from '../../iterator/index.mjs';
|
|
4
|
+
import { asNegativeInt, isNegativeInt, NegativeInt } from './negative-int.mjs';
|
|
5
|
+
|
|
6
|
+
describe('NegativeInt test', () => {
|
|
7
|
+
describe(asNegativeInt, () => {
|
|
8
|
+
test('accepts valid negative integers', () => {
|
|
9
|
+
expect(() => asNegativeInt(-1)).not.toThrow();
|
|
10
|
+
|
|
11
|
+
expect(() => asNegativeInt(-1000)).not.toThrow();
|
|
12
|
+
|
|
13
|
+
expect(() => asNegativeInt(Number.MIN_SAFE_INTEGER)).not.toThrow();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('rejects zero and positive integers', () => {
|
|
17
|
+
expect(() => asNegativeInt(0)).toThrow(TypeError);
|
|
18
|
+
|
|
19
|
+
expect(() => asNegativeInt(1)).toThrow(TypeError);
|
|
20
|
+
|
|
21
|
+
expect(() => asNegativeInt(Number.MAX_SAFE_INTEGER)).toThrow(TypeError);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('rejects non-integers', () => {
|
|
25
|
+
expect(() => asNegativeInt(Number.NaN)).toThrow(TypeError);
|
|
26
|
+
|
|
27
|
+
expect(() => asNegativeInt(Number.NEGATIVE_INFINITY)).toThrow(TypeError);
|
|
28
|
+
|
|
29
|
+
expect(() => asNegativeInt(-1.5)).toThrow(TypeError);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('returns the same value for valid inputs', () => {
|
|
33
|
+
expect(asNegativeInt(-5)).toBe(-5);
|
|
34
|
+
|
|
35
|
+
expect(asNegativeInt(Number.MIN_SAFE_INTEGER)).toBe(
|
|
36
|
+
Number.MIN_SAFE_INTEGER,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe(isNegativeInt, () => {
|
|
42
|
+
test('correctly identifies negative integers', () => {
|
|
43
|
+
assert.isTrue(isNegativeInt(-1));
|
|
44
|
+
|
|
45
|
+
assert.isTrue(isNegativeInt(-1000));
|
|
46
|
+
|
|
47
|
+
assert.isFalse(isNegativeInt(0));
|
|
48
|
+
|
|
49
|
+
assert.isFalse(isNegativeInt(1));
|
|
50
|
+
|
|
51
|
+
assert.isFalse(isNegativeInt(-1.5));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('NegativeInt.is', () => {
|
|
56
|
+
test('works as a type guard', () => {
|
|
57
|
+
const value: number = -42;
|
|
58
|
+
|
|
59
|
+
if (NegativeInt.is(value)) {
|
|
60
|
+
expectType<typeof value, typeof value & NegativeInt>('=');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('NegativeInt.MAX_VALUE', () => {
|
|
66
|
+
test('is -1', () => {
|
|
67
|
+
expect(NegativeInt.MAX_VALUE).toBe(-1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('NegativeInt.abs', () => {
|
|
72
|
+
test('returns the absolute value as a positive integer', () => {
|
|
73
|
+
expect(NegativeInt.abs(asNegativeInt(-5))).toBe(5);
|
|
74
|
+
|
|
75
|
+
expect(NegativeInt.abs(asNegativeInt(-1))).toBe(1);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('result type is PositiveInt', () => {
|
|
79
|
+
expectType<ReturnType<typeof NegativeInt.abs>, PositiveInt>('=');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('NegativeInt.min', () => {
|
|
84
|
+
test('returns the smaller value', () => {
|
|
85
|
+
expect(NegativeInt.min(-5, -10)).toBe(-10);
|
|
86
|
+
|
|
87
|
+
expect(NegativeInt.min(-1, -2)).toBe(-2);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('NegativeInt.max', () => {
|
|
92
|
+
test('returns the larger value', () => {
|
|
93
|
+
expect(NegativeInt.max(-5, -10)).toBe(-5);
|
|
94
|
+
|
|
95
|
+
expect(NegativeInt.max(-1, -2)).toBe(-1);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('NegativeInt.clamp', () => {
|
|
100
|
+
test('returns the same value if within range', () => {
|
|
101
|
+
expect(NegativeInt.clamp(-5)).toBe(-5);
|
|
102
|
+
|
|
103
|
+
expect(NegativeInt.clamp(-1000)).toBe(-1000);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('clamps non-negative values to MAX_VALUE (-1)', () => {
|
|
107
|
+
expect(NegativeInt.clamp(0)).toBe(-1);
|
|
108
|
+
|
|
109
|
+
expect(NegativeInt.clamp(5)).toBe(-1);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('NegativeInt.add', () => {
|
|
114
|
+
test('adds two negative integers', () => {
|
|
115
|
+
expect(NegativeInt.add(-5, -3)).toBe(-8);
|
|
116
|
+
|
|
117
|
+
expect(NegativeInt.add(-1, -1)).toBe(-2);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('NegativeInt.sub', () => {
|
|
122
|
+
test('subtracts two negative integers', () => {
|
|
123
|
+
expect(NegativeInt.sub(-10, -3)).toBe(-7);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('clamps result to MAX_VALUE (-1) when result is non-negative', () => {
|
|
127
|
+
expect(NegativeInt.sub(-3, -10)).toBe(-1);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('NegativeInt.pow', () => {
|
|
132
|
+
test('raises to power', () => {
|
|
133
|
+
expect(NegativeInt.pow(-2, -1)).toBeDefined();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('NegativeInt.random', () => {
|
|
138
|
+
test('generates values within range', () => {
|
|
139
|
+
for (const _ of range(100)) {
|
|
140
|
+
const value = NegativeInt.random();
|
|
141
|
+
|
|
142
|
+
assert.isTrue(isNegativeInt(value));
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type NegativeSafeInt as TtfImported_NegativeSafeInt,
|
|
3
|
+
type WithSmallInt,
|
|
4
|
+
} from 'ts-type-forge';
|
|
5
|
+
import { TsDataForgeInternals } from '../refined-number-utils.mjs';
|
|
6
|
+
import { PositiveSafeInt } from './positive-safe-int.mjs';
|
|
7
|
+
|
|
8
|
+
export type NegativeSafeInt = TtfImported_NegativeSafeInt;
|
|
9
|
+
|
|
10
|
+
type ElementType = NegativeSafeInt;
|
|
11
|
+
|
|
12
|
+
const typeNameInMessage = 'a negative safe integer';
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
MAX_VALUE,
|
|
16
|
+
MIN_VALUE,
|
|
17
|
+
add,
|
|
18
|
+
castType,
|
|
19
|
+
clamp,
|
|
20
|
+
is,
|
|
21
|
+
max: max_,
|
|
22
|
+
min: min_,
|
|
23
|
+
pow,
|
|
24
|
+
random,
|
|
25
|
+
sub,
|
|
26
|
+
} = TsDataForgeInternals.RefinedNumberUtils.operatorsForInteger<
|
|
27
|
+
ElementType,
|
|
28
|
+
number,
|
|
29
|
+
-1
|
|
30
|
+
>({
|
|
31
|
+
integerOrSafeInteger: 'SafeInteger',
|
|
32
|
+
nonZero: true,
|
|
33
|
+
MIN_VALUE: Number.MIN_SAFE_INTEGER,
|
|
34
|
+
MAX_VALUE: -1,
|
|
35
|
+
typeNameInMessage,
|
|
36
|
+
} as const);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Returns the absolute value of a negative safe integer.
|
|
40
|
+
*
|
|
41
|
+
* The absolute value of a negative safe integer is always a positive safe
|
|
42
|
+
* integer (`>= 1`), so the result is typed as a {@link PositiveSafeInt}.
|
|
43
|
+
*
|
|
44
|
+
* @param x - The negative safe integer.
|
|
45
|
+
* @returns `|x|` as a PositiveSafeInt.
|
|
46
|
+
*/
|
|
47
|
+
const abs = (x: WithSmallInt<ElementType>): PositiveSafeInt =>
|
|
48
|
+
PositiveSafeInt.clamp(Math.abs(x));
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Checks if a number is a NegativeSafeInt (a negative safe integer in the range
|
|
52
|
+
* `[Number.MIN_SAFE_INTEGER, -1]`).
|
|
53
|
+
*
|
|
54
|
+
* @param value The value to check.
|
|
55
|
+
* @returns `true` if the value is a NegativeSafeInt, `false` otherwise.
|
|
56
|
+
*/
|
|
57
|
+
export const isNegativeSafeInt = is;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Casts a number to a NegativeSafeInt type.
|
|
61
|
+
*
|
|
62
|
+
* @param value The value to cast.
|
|
63
|
+
* @returns The value as a NegativeSafeInt type.
|
|
64
|
+
* @throws {TypeError} If the value is not a negative safe integer.
|
|
65
|
+
*/
|
|
66
|
+
export const asNegativeSafeInt = castType;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Namespace providing type-safe arithmetic operations for negative safe
|
|
70
|
+
* integers.
|
|
71
|
+
*
|
|
72
|
+
* NegativeSafeInt represents safe integers that are strictly less than zero
|
|
73
|
+
* (`[Number.MIN_SAFE_INTEGER, -1]`). Operations that stay within the negative
|
|
74
|
+
* safe integers clamp their results to the valid range, while operations whose
|
|
75
|
+
* result leaves the set (`mul`, `div`, `abs`) are typed to reflect the actual
|
|
76
|
+
* sign of the result.
|
|
77
|
+
*/
|
|
78
|
+
export const NegativeSafeInt = {
|
|
79
|
+
/**
|
|
80
|
+
* Type guard to check if a value is a NegativeSafeInt.
|
|
81
|
+
*
|
|
82
|
+
* @param value The value to check.
|
|
83
|
+
* @returns `true` if the value is a negative safe integer, `false` otherwise.
|
|
84
|
+
*/
|
|
85
|
+
is,
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The minimum value for a negative safe integer.
|
|
89
|
+
*
|
|
90
|
+
* @readonly
|
|
91
|
+
*/
|
|
92
|
+
MIN_VALUE,
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The maximum value for a negative safe integer.
|
|
96
|
+
*
|
|
97
|
+
* @readonly
|
|
98
|
+
*/
|
|
99
|
+
MAX_VALUE,
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Returns the absolute value of a negative safe integer.
|
|
103
|
+
*
|
|
104
|
+
* @param a The negative safe integer.
|
|
105
|
+
* @returns The absolute value as a PositiveSafeInt.
|
|
106
|
+
*/
|
|
107
|
+
abs,
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns the smaller of two negative safe integers.
|
|
111
|
+
*
|
|
112
|
+
* @param a The first negative safe integer.
|
|
113
|
+
* @param b The second negative safe integer.
|
|
114
|
+
* @returns The minimum value as a NegativeSafeInt.
|
|
115
|
+
*/
|
|
116
|
+
min: min_,
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns the larger of two negative safe integers.
|
|
120
|
+
*
|
|
121
|
+
* @param a The first negative safe integer.
|
|
122
|
+
* @param b The second negative safe integer.
|
|
123
|
+
* @returns The maximum value as a NegativeSafeInt.
|
|
124
|
+
*/
|
|
125
|
+
max: max_,
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Clamps a number to the NegativeSafeInt range.
|
|
129
|
+
*
|
|
130
|
+
* @param value The number to clamp.
|
|
131
|
+
* @returns The value clamped to `[Number.MIN_SAFE_INTEGER, -1]` as a
|
|
132
|
+
* NegativeSafeInt.
|
|
133
|
+
*/
|
|
134
|
+
clamp,
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Generates a random NegativeSafeInt value within the valid range.
|
|
138
|
+
*
|
|
139
|
+
* @returns A random NegativeSafeInt between Number.MIN_SAFE_INTEGER and -1.
|
|
140
|
+
*/
|
|
141
|
+
random,
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Raises a negative safe integer to the power of another negative safe
|
|
145
|
+
* integer.
|
|
146
|
+
*
|
|
147
|
+
* @param a The base negative safe integer.
|
|
148
|
+
* @param b The exponent negative safe integer.
|
|
149
|
+
* @returns `a ** b` clamped to the NegativeSafeInt range.
|
|
150
|
+
*/
|
|
151
|
+
pow,
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Adds two negative safe integers.
|
|
155
|
+
*
|
|
156
|
+
* @param a The first negative safe integer.
|
|
157
|
+
* @param b The second negative safe integer.
|
|
158
|
+
* @returns `a + b` clamped to the NegativeSafeInt range.
|
|
159
|
+
*/
|
|
160
|
+
add,
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Subtracts one negative safe integer from another.
|
|
164
|
+
*
|
|
165
|
+
* The mathematical result can be positive, so it is clamped to the
|
|
166
|
+
* NegativeSafeInt range (maximum `-1`).
|
|
167
|
+
*
|
|
168
|
+
* @param a The minuend negative safe integer.
|
|
169
|
+
* @param b The subtrahend negative safe integer.
|
|
170
|
+
* @returns `a - b` clamped to the NegativeSafeInt range.
|
|
171
|
+
*/
|
|
172
|
+
sub,
|
|
173
|
+
} as const;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type PositiveSafeInt } from 'ts-type-forge';
|
|
2
|
+
import { expectType } from '../../expect-type.mjs';
|
|
3
|
+
import { range } from '../../iterator/index.mjs';
|
|
4
|
+
import {
|
|
5
|
+
asNegativeSafeInt,
|
|
6
|
+
isNegativeSafeInt,
|
|
7
|
+
NegativeSafeInt,
|
|
8
|
+
} from './negative-safe-int.mjs';
|
|
9
|
+
|
|
10
|
+
describe('NegativeSafeInt test', () => {
|
|
11
|
+
describe(asNegativeSafeInt, () => {
|
|
12
|
+
test('accepts valid negative safe integers', () => {
|
|
13
|
+
expect(() => asNegativeSafeInt(-1)).not.toThrow();
|
|
14
|
+
|
|
15
|
+
expect(() => asNegativeSafeInt(-1000)).not.toThrow();
|
|
16
|
+
|
|
17
|
+
expect(() => asNegativeSafeInt(Number.MIN_SAFE_INTEGER)).not.toThrow();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('rejects zero and positive integers', () => {
|
|
21
|
+
expect(() => asNegativeSafeInt(0)).toThrow(TypeError);
|
|
22
|
+
|
|
23
|
+
expect(() => asNegativeSafeInt(1)).toThrow(TypeError);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('rejects unsafe and non-integers', () => {
|
|
27
|
+
expect(() => asNegativeSafeInt(Number.MIN_SAFE_INTEGER - 1)).toThrow(
|
|
28
|
+
TypeError,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(() => asNegativeSafeInt(Number.NEGATIVE_INFINITY)).toThrow(
|
|
32
|
+
TypeError,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(() => asNegativeSafeInt(-1.5)).toThrow(TypeError);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe(isNegativeSafeInt, () => {
|
|
40
|
+
test('correctly identifies negative safe integers', () => {
|
|
41
|
+
assert.isTrue(isNegativeSafeInt(-1));
|
|
42
|
+
|
|
43
|
+
assert.isTrue(isNegativeSafeInt(Number.MIN_SAFE_INTEGER));
|
|
44
|
+
|
|
45
|
+
assert.isFalse(isNegativeSafeInt(0));
|
|
46
|
+
|
|
47
|
+
assert.isFalse(isNegativeSafeInt(1));
|
|
48
|
+
|
|
49
|
+
assert.isFalse(isNegativeSafeInt(Number.MIN_SAFE_INTEGER - 1));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('NegativeSafeInt.is', () => {
|
|
54
|
+
test('works as a type guard', () => {
|
|
55
|
+
const value: number = -42;
|
|
56
|
+
|
|
57
|
+
if (NegativeSafeInt.is(value)) {
|
|
58
|
+
expectType<typeof value, typeof value & NegativeSafeInt>('=');
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('NegativeSafeInt.MAX_VALUE / MIN_VALUE', () => {
|
|
64
|
+
test('has the expected bounds', () => {
|
|
65
|
+
expect(NegativeSafeInt.MAX_VALUE).toBe(-1);
|
|
66
|
+
|
|
67
|
+
expect(NegativeSafeInt.MIN_VALUE).toBe(Number.MIN_SAFE_INTEGER);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('NegativeSafeInt.abs', () => {
|
|
72
|
+
test('returns the absolute value as a positive safe integer', () => {
|
|
73
|
+
expect(NegativeSafeInt.abs(asNegativeSafeInt(-5))).toBe(5);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('result type is PositiveSafeInt', () => {
|
|
77
|
+
expectType<ReturnType<typeof NegativeSafeInt.abs>, PositiveSafeInt>('=');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('NegativeSafeInt.min / max', () => {
|
|
82
|
+
test('returns the expected extremum', () => {
|
|
83
|
+
expect(NegativeSafeInt.min(-5, -10)).toBe(-10);
|
|
84
|
+
|
|
85
|
+
expect(NegativeSafeInt.max(-5, -10)).toBe(-5);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('NegativeSafeInt.clamp', () => {
|
|
90
|
+
test('clamps to the valid range', () => {
|
|
91
|
+
expect(NegativeSafeInt.clamp(-5)).toBe(-5);
|
|
92
|
+
|
|
93
|
+
expect(NegativeSafeInt.clamp(0)).toBe(-1);
|
|
94
|
+
|
|
95
|
+
expect(NegativeSafeInt.clamp(Number.MIN_SAFE_INTEGER - 100)).toBe(
|
|
96
|
+
Number.MIN_SAFE_INTEGER,
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('NegativeSafeInt.add / sub', () => {
|
|
102
|
+
test('adds and subtracts within the range', () => {
|
|
103
|
+
expect(NegativeSafeInt.add(-5, -3)).toBe(-8);
|
|
104
|
+
|
|
105
|
+
expect(NegativeSafeInt.sub(-10, -3)).toBe(-7);
|
|
106
|
+
|
|
107
|
+
expect(NegativeSafeInt.sub(-3, -10)).toBe(-1);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('NegativeSafeInt.random', () => {
|
|
112
|
+
test('generates values within range', () => {
|
|
113
|
+
for (const _ of range(100)) {
|
|
114
|
+
const value = NegativeSafeInt.random();
|
|
115
|
+
|
|
116
|
+
assert.isTrue(isNegativeSafeInt(value));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { type NonPositiveFiniteNumber as TtfImported_NonPositiveFiniteNumber } from 'ts-type-forge';
|
|
2
|
+
import { TsDataForgeInternals } from '../refined-number-utils.mjs';
|
|
3
|
+
|
|
4
|
+
export type NonPositiveFiniteNumber = TtfImported_NonPositiveFiniteNumber;
|
|
5
|
+
|
|
6
|
+
type ElementType = NonPositiveFiniteNumber;
|
|
7
|
+
|
|
8
|
+
const typeNameInMessage = 'a non-positive finite number';
|
|
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.operatorsForFloat<
|
|
22
|
+
ElementType,
|
|
23
|
+
number,
|
|
24
|
+
0
|
|
25
|
+
>({
|
|
26
|
+
MIN_VALUE: Number.MAX_VALUE * -1,
|
|
27
|
+
MAX_VALUE: 0,
|
|
28
|
+
typeNameInMessage,
|
|
29
|
+
} as const);
|
|
30
|
+
|
|
31
|
+
const floor = (
|
|
32
|
+
x: ElementType,
|
|
33
|
+
): TsDataForgeInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
34
|
+
TsDataForgeInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
35
|
+
> =>
|
|
36
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
37
|
+
Math.floor(
|
|
38
|
+
x,
|
|
39
|
+
) as TsDataForgeInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
40
|
+
TsDataForgeInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
const ceil = (
|
|
44
|
+
x: ElementType,
|
|
45
|
+
): TsDataForgeInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
46
|
+
TsDataForgeInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
47
|
+
> =>
|
|
48
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
49
|
+
Math.ceil(x) as TsDataForgeInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
50
|
+
TsDataForgeInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
51
|
+
>;
|
|
52
|
+
|
|
53
|
+
const round = (
|
|
54
|
+
x: ElementType,
|
|
55
|
+
): TsDataForgeInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
56
|
+
TsDataForgeInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
57
|
+
> =>
|
|
58
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
59
|
+
Math.round(
|
|
60
|
+
x,
|
|
61
|
+
) as TsDataForgeInternals.RefinedNumberUtils.RemoveNonZeroBrandKey<
|
|
62
|
+
TsDataForgeInternals.RefinedNumberUtils.ToInt<ElementType>
|
|
63
|
+
>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Checks if a number is a NonPositiveFiniteNumber (a finite number <= 0).
|
|
67
|
+
*
|
|
68
|
+
* @param value The value to check.
|
|
69
|
+
* @returns `true` if the value is a NonPositiveFiniteNumber, `false` otherwise.
|
|
70
|
+
*/
|
|
71
|
+
export const isNonPositiveFiniteNumber = is;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Casts a number to a NonPositiveFiniteNumber type.
|
|
75
|
+
*
|
|
76
|
+
* @param value The value to cast.
|
|
77
|
+
* @returns The value as a NonPositiveFiniteNumber type.
|
|
78
|
+
* @throws {TypeError} If the value is not a non-positive finite number.
|
|
79
|
+
*/
|
|
80
|
+
export const asNonPositiveFiniteNumber = castType;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Namespace providing type-safe arithmetic operations for non-positive finite
|
|
84
|
+
* numbers.
|
|
85
|
+
*
|
|
86
|
+
* All operations maintain the non-positive constraint by clamping positive
|
|
87
|
+
* results to MAX_VALUE (0), while ensuring results remain finite (excluding NaN
|
|
88
|
+
* and Infinity). This type is useful for representing quantities that must
|
|
89
|
+
* always be non-positive, such as debts, penalties, and negative offsets.
|
|
90
|
+
*/
|
|
91
|
+
export const NonPositiveFiniteNumber = {
|
|
92
|
+
/**
|
|
93
|
+
* Type guard to check if a value is a NonPositiveFiniteNumber.
|
|
94
|
+
*
|
|
95
|
+
* @param value The value to check.
|
|
96
|
+
* @returns `true` if the value is a non-positive finite number, `false`
|
|
97
|
+
* otherwise.
|
|
98
|
+
*/
|
|
99
|
+
is,
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The maximum value for a non-positive finite number.
|
|
103
|
+
*
|
|
104
|
+
* @readonly
|
|
105
|
+
*/
|
|
106
|
+
MAX_VALUE,
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Returns the smaller of two NonPositiveFiniteNumber values.
|
|
110
|
+
*
|
|
111
|
+
* @param a The first NonPositiveFiniteNumber.
|
|
112
|
+
* @param b The second NonPositiveFiniteNumber.
|
|
113
|
+
* @returns The minimum value as a NonPositiveFiniteNumber.
|
|
114
|
+
*/
|
|
115
|
+
min: min_,
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns the larger of two NonPositiveFiniteNumber values.
|
|
119
|
+
*
|
|
120
|
+
* @param a The first NonPositiveFiniteNumber.
|
|
121
|
+
* @param b The second NonPositiveFiniteNumber.
|
|
122
|
+
* @returns The maximum value as a NonPositiveFiniteNumber.
|
|
123
|
+
*/
|
|
124
|
+
max: max_,
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Clamps a number to the non-positive finite range.
|
|
128
|
+
*
|
|
129
|
+
* @param value The number to clamp.
|
|
130
|
+
* @returns The value clamped to (-∞, 0] as a NonPositiveFiniteNumber.
|
|
131
|
+
*/
|
|
132
|
+
clamp,
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Rounds down a NonPositiveFiniteNumber to the nearest integer.
|
|
136
|
+
*
|
|
137
|
+
* @param x The NonPositiveFiniteNumber to round down.
|
|
138
|
+
* @returns The floor value as a NonPositiveInt (can be 0).
|
|
139
|
+
*/
|
|
140
|
+
floor,
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Rounds up a NonPositiveFiniteNumber to the nearest integer.
|
|
144
|
+
*
|
|
145
|
+
* @param x The NonPositiveFiniteNumber to round up.
|
|
146
|
+
* @returns The ceiling value as a NegativeInt (always <= -1) or 0.
|
|
147
|
+
*/
|
|
148
|
+
ceil,
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Rounds a NonPositiveFiniteNumber to the nearest integer.
|
|
152
|
+
*
|
|
153
|
+
* @param x The NonPositiveFiniteNumber to round.
|
|
154
|
+
* @returns The rounded value as a NonPositiveInt (can be 0 if x > -0.5).
|
|
155
|
+
*/
|
|
156
|
+
round,
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Generates a random NonPositiveFiniteNumber value.
|
|
160
|
+
*
|
|
161
|
+
* @returns A random non-positive finite number.
|
|
162
|
+
*/
|
|
163
|
+
random,
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Raises a NonPositiveFiniteNumber to the power of another NonPositiveFiniteNumber.
|
|
167
|
+
*
|
|
168
|
+
* @param a The base NonPositiveFiniteNumber.
|
|
169
|
+
* @param b The exponent NonPositiveFiniteNumber.
|
|
170
|
+
* @returns `a ** b` clamped to (-∞, 0] as a NonPositiveFiniteNumber.
|
|
171
|
+
*/
|
|
172
|
+
pow,
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Adds two NonPositiveFiniteNumber values.
|
|
176
|
+
*
|
|
177
|
+
* @param a The first NonPositiveFiniteNumber.
|
|
178
|
+
* @param b The second NonPositiveFiniteNumber.
|
|
179
|
+
* @returns `a + b` clamped to (-∞, 0] as a NonPositiveFiniteNumber.
|
|
180
|
+
*/
|
|
181
|
+
add,
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Subtracts one NonPositiveFiniteNumber from another.
|
|
185
|
+
*
|
|
186
|
+
* @param a The minuend NonPositiveFiniteNumber.
|
|
187
|
+
* @param b The subtrahend NonPositiveFiniteNumber.
|
|
188
|
+
* @returns `a - b` clamped to (-∞, 0] as a NonPositiveFiniteNumber (maximum 0).
|
|
189
|
+
*/
|
|
190
|
+
sub,
|
|
191
|
+
} as const;
|