ts-data-forge 8.0.0 → 9.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/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
- package/dist/entry-point.mjs +1 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/expect-type.d.mts.map +1 -1
- package/dist/expect-type.mjs.map +1 -1
- package/dist/functional/ternary-result/ternary-result.d.mts.map +1 -1
- package/dist/guard/index.d.mts +1 -0
- package/dist/guard/index.d.mts.map +1 -1
- package/dist/guard/index.mjs +1 -0
- package/dist/guard/index.mjs.map +1 -1
- package/dist/guard/is-length-bounded-string.d.mts +164 -0
- package/dist/guard/is-length-bounded-string.d.mts.map +1 -0
- package/dist/guard/is-length-bounded-string.mjs +164 -0
- package/dist/guard/is-length-bounded-string.mjs.map +1 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/number/branded-types/int.d.mts +1 -1
- package/dist/number/branded-types/int16.d.mts +1 -1
- package/dist/number/branded-types/int32.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/positive-int.d.mts +1 -1
- package/dist/number/branded-types/positive-int16.d.mts +1 -1
- package/dist/number/branded-types/positive-int32.d.mts +1 -1
- package/dist/number/branded-types/positive-safe-int.d.mts +1 -1
- package/dist/number/branded-types/positive-uint16.d.mts +1 -1
- package/dist/number/branded-types/positive-uint32.d.mts +1 -1
- package/dist/number/branded-types/safe-int.d.mts +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/refined-number-utils.d.mts.map +1 -1
- package/dist/number/refined-number-utils.mjs.map +1 -1
- package/dist/object/object.d.mts.map +1 -1
- package/dist/object/object.mjs.map +1 -1
- package/package.json +10 -10
- package/src/array/impl/array-utils-transformation.mts +1 -2
- package/src/array/impl/array-utils-transformation.test.mts +3 -36
- package/src/array/impl/array-utils-validation.test.mts +1 -3
- package/src/expect-type.mts +4 -5
- package/src/functional/ternary-result/ternary-result.mts +2 -6
- package/src/guard/index.mts +1 -0
- package/src/guard/is-length-bounded-string.mts +199 -0
- package/src/guard/is-length-bounded-string.test.mts +170 -0
- package/src/number/refined-number-utils.mts +1 -9
- package/src/object/object.mts +25 -23
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BoundedLengthString,
|
|
3
|
+
type FixedLengthString,
|
|
4
|
+
type MaxLengthString,
|
|
5
|
+
type MinLengthString,
|
|
6
|
+
type NonEmptyString,
|
|
7
|
+
} from 'ts-type-forge';
|
|
8
|
+
import { expectType } from '../expect-type.mjs';
|
|
9
|
+
import {
|
|
10
|
+
isBoundedLengthString,
|
|
11
|
+
isFixedLengthString,
|
|
12
|
+
isMaxLengthString,
|
|
13
|
+
isMinLengthString,
|
|
14
|
+
} from './is-length-bounded-string.mjs';
|
|
15
|
+
|
|
16
|
+
describe(isMinLengthString, () => {
|
|
17
|
+
test('should return true when the string is long enough', () => {
|
|
18
|
+
assert.isTrue(isMinLengthString('hello', 3));
|
|
19
|
+
|
|
20
|
+
assert.isTrue(isMinLengthString('hello', 5));
|
|
21
|
+
|
|
22
|
+
assert.isTrue(isMinLengthString('', 0));
|
|
23
|
+
|
|
24
|
+
assert.isTrue(isMinLengthString(' ', 1)); // Space counts
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should return false when the string is too short', () => {
|
|
28
|
+
assert.isFalse(isMinLengthString('hi', 3));
|
|
29
|
+
|
|
30
|
+
assert.isFalse(isMinLengthString('', 1));
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should measure length in UTF-16 code units', () => {
|
|
34
|
+
assert.isTrue(isMinLengthString('🎉', 2)); // Surrogate pair
|
|
35
|
+
|
|
36
|
+
assert.isFalse(isMinLengthString('🎉', 3));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should act as a type guard', () => {
|
|
40
|
+
const value: string = 'very-secret-password';
|
|
41
|
+
|
|
42
|
+
if (isMinLengthString(value, 12)) {
|
|
43
|
+
expectType<typeof value, MinLengthString<12>>('<=');
|
|
44
|
+
|
|
45
|
+
expectType<typeof value, NonEmptyString>('<='); // 12 >= 1
|
|
46
|
+
|
|
47
|
+
expectType<typeof value, MinLengthString<16>>('!<=');
|
|
48
|
+
|
|
49
|
+
expect(value.length).toBeGreaterThanOrEqual(12);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('should preserve literal string types', () => {
|
|
54
|
+
const literal = 'hello';
|
|
55
|
+
|
|
56
|
+
if (isMinLengthString(literal, 3)) {
|
|
57
|
+
expectType<typeof literal, 'hello'>('<=');
|
|
58
|
+
|
|
59
|
+
expectType<typeof literal, MinLengthString<3>>('<=');
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe(isMaxLengthString, () => {
|
|
65
|
+
test('should return true when the string is short enough', () => {
|
|
66
|
+
assert.isTrue(isMaxLengthString('hello', 10));
|
|
67
|
+
|
|
68
|
+
assert.isTrue(isMaxLengthString('hello', 5));
|
|
69
|
+
|
|
70
|
+
assert.isTrue(isMaxLengthString('', 0));
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should return false when the string is too long', () => {
|
|
74
|
+
assert.isFalse(isMaxLengthString('hello', 3));
|
|
75
|
+
|
|
76
|
+
assert.isFalse(isMaxLengthString(' ', 0));
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('should measure length in UTF-16 code units', () => {
|
|
80
|
+
assert.isFalse(isMaxLengthString('🎉', 1)); // Surrogate pair
|
|
81
|
+
|
|
82
|
+
assert.isTrue(isMaxLengthString('🎉', 2));
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('should act as a type guard', () => {
|
|
86
|
+
const value: string = 'noshiro';
|
|
87
|
+
|
|
88
|
+
if (isMaxLengthString(value, 32)) {
|
|
89
|
+
expectType<typeof value, MaxLengthString<32>>('<=');
|
|
90
|
+
|
|
91
|
+
expectType<typeof value, MaxLengthString<64>>('<='); // 32 <= 64
|
|
92
|
+
|
|
93
|
+
expectType<typeof value, MaxLengthString<16>>('!<=');
|
|
94
|
+
|
|
95
|
+
expect(value.length).toBeLessThanOrEqual(32);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe(isBoundedLengthString, () => {
|
|
101
|
+
test('should return true when the length is within the range', () => {
|
|
102
|
+
assert.isTrue(isBoundedLengthString('user-12345678', 8, 16));
|
|
103
|
+
|
|
104
|
+
assert.isTrue(isBoundedLengthString('12345678', 8, 16)); // Lower bound (inclusive)
|
|
105
|
+
|
|
106
|
+
assert.isTrue(isBoundedLengthString('1234567890123456', 8, 16)); // Upper bound (inclusive)
|
|
107
|
+
|
|
108
|
+
assert.isTrue(isBoundedLengthString('', 0, 0));
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('should return false when the length is out of range', () => {
|
|
112
|
+
assert.isFalse(isBoundedLengthString('user', 8, 16));
|
|
113
|
+
|
|
114
|
+
assert.isFalse(isBoundedLengthString('12345678901234567', 8, 16));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('should act as a type guard', () => {
|
|
118
|
+
const value: string = 'user-12345678';
|
|
119
|
+
|
|
120
|
+
if (isBoundedLengthString(value, 8, 16)) {
|
|
121
|
+
expectType<typeof value, BoundedLengthString<8, 16>>('<=');
|
|
122
|
+
|
|
123
|
+
expectType<typeof value, BoundedLengthString<1, 255>>('<='); // [8, 16] ⊆ [1, 255]
|
|
124
|
+
|
|
125
|
+
expectType<typeof value, MinLengthString<8>>('<=');
|
|
126
|
+
|
|
127
|
+
expectType<typeof value, MaxLengthString<16>>('<=');
|
|
128
|
+
|
|
129
|
+
expectType<typeof value, NonEmptyString>('<='); // 8 >= 1
|
|
130
|
+
|
|
131
|
+
expectType<typeof value, BoundedLengthString<10, 16>>('!<=');
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe(isFixedLengthString, () => {
|
|
137
|
+
test('should return true only for the exact length', () => {
|
|
138
|
+
assert.isTrue(isFixedLengthString('JP', 2));
|
|
139
|
+
|
|
140
|
+
assert.isTrue(isFixedLengthString('', 0));
|
|
141
|
+
|
|
142
|
+
assert.isFalse(isFixedLengthString('JPN', 2));
|
|
143
|
+
|
|
144
|
+
assert.isFalse(isFixedLengthString('J', 2));
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('should measure length in UTF-16 code units', () => {
|
|
148
|
+
assert.isTrue(isFixedLengthString('🎉', 2)); // Surrogate pair
|
|
149
|
+
|
|
150
|
+
assert.isFalse(isFixedLengthString('🎉', 1));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('should act as a type guard', () => {
|
|
154
|
+
const value: string = 'JP';
|
|
155
|
+
|
|
156
|
+
if (isFixedLengthString(value, 2)) {
|
|
157
|
+
expectType<typeof value, FixedLengthString<2>>('<=');
|
|
158
|
+
|
|
159
|
+
expectType<typeof value, BoundedLengthString<2, 2>>('<=');
|
|
160
|
+
|
|
161
|
+
expectType<typeof value, MaxLengthString<5>>('<='); // 2 <= 5
|
|
162
|
+
|
|
163
|
+
expectType<typeof value, MinLengthString<1>>('<='); // 2 >= 1
|
|
164
|
+
|
|
165
|
+
expectType<typeof value, NonEmptyString>('<=');
|
|
166
|
+
|
|
167
|
+
expectType<typeof value, FixedLengthString<3>>('!<=');
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
@@ -185,15 +185,7 @@ export namespace TsDataForgeInternals {
|
|
|
185
185
|
}>;
|
|
186
186
|
|
|
187
187
|
type BaseKeys =
|
|
188
|
-
| '
|
|
189
|
-
| 'div'
|
|
190
|
-
| 'is'
|
|
191
|
-
| 'max'
|
|
192
|
-
| 'min'
|
|
193
|
-
| 'mul'
|
|
194
|
-
| 'pow'
|
|
195
|
-
| 'random'
|
|
196
|
-
| 'sub';
|
|
188
|
+
'add' | 'div' | 'is' | 'max' | 'min' | 'mul' | 'pow' | 'random' | 'sub';
|
|
197
189
|
|
|
198
190
|
type FloatMethods = 'ceil' | 'floor' | 'round';
|
|
199
191
|
|
package/src/object/object.mts
CHANGED
|
@@ -224,11 +224,9 @@ export namespace Obj {
|
|
|
224
224
|
const Keys extends readonly (keyof R)[],
|
|
225
225
|
>(
|
|
226
226
|
...args:
|
|
227
|
-
|
|
228
|
-
| readonly [keys: readonly PropertyKey[]]
|
|
227
|
+
readonly [record: R, keys: Keys] | readonly [keys: readonly PropertyKey[]]
|
|
229
228
|
):
|
|
230
|
-
| Omit<R, ArrayElement<Keys>>
|
|
231
|
-
| ((record: R) => Omit<R, ArrayElement<Keys>>) {
|
|
229
|
+
Omit<R, ArrayElement<Keys>> | ((record: R) => Omit<R, ArrayElement<Keys>>) {
|
|
232
230
|
switch (args.length) {
|
|
233
231
|
case 2: {
|
|
234
232
|
const [record, keys] = args;
|
|
@@ -644,32 +642,36 @@ declare namespace TsDataForgeInternals {
|
|
|
644
642
|
readonly [K in keyof B as {} extends Pick<B, K> ? never : K]: B[K];
|
|
645
643
|
} & {
|
|
646
644
|
// 2. Optional properties from B that are NOT in A
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
?
|
|
651
|
-
|
|
652
|
-
|
|
645
|
+
readonly [
|
|
646
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
647
|
+
K in keyof B as {} extends Pick<B, K>
|
|
648
|
+
? K extends keyof A
|
|
649
|
+
? never
|
|
650
|
+
: K
|
|
651
|
+
: never
|
|
652
|
+
]?: B[K];
|
|
653
653
|
} & {
|
|
654
654
|
// 3. Optional properties from B that ARE in A (create union)
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
? K
|
|
655
|
+
readonly [
|
|
656
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
657
|
+
K in keyof B as {} extends Pick<B, K>
|
|
658
|
+
? K extends keyof A
|
|
659
|
+
? K
|
|
660
|
+
: never
|
|
659
661
|
: never
|
|
660
|
-
|
|
662
|
+
]?: K extends keyof A ? A[K] | B[K] : never;
|
|
661
663
|
} & {
|
|
662
664
|
// 4. Required properties only in A (not overridden by B)
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
? never
|
|
666
|
-
|
|
665
|
+
readonly [
|
|
666
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
667
|
+
K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? never : K
|
|
668
|
+
]: A[K];
|
|
667
669
|
} & {
|
|
668
670
|
// 5. Optional properties only in A (not overridden by B)
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
? K
|
|
672
|
-
|
|
671
|
+
readonly [
|
|
672
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
673
|
+
K in Exclude<keyof A, keyof B> as {} extends Pick<A, K> ? K : never
|
|
674
|
+
]?: A[K];
|
|
673
675
|
} extends infer O
|
|
674
676
|
? Readonly<
|
|
675
677
|
{
|