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.
Files changed (48) hide show
  1. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  2. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  3. package/dist/entry-point.mjs +1 -0
  4. package/dist/entry-point.mjs.map +1 -1
  5. package/dist/expect-type.d.mts.map +1 -1
  6. package/dist/expect-type.mjs.map +1 -1
  7. package/dist/functional/ternary-result/ternary-result.d.mts.map +1 -1
  8. package/dist/guard/index.d.mts +1 -0
  9. package/dist/guard/index.d.mts.map +1 -1
  10. package/dist/guard/index.mjs +1 -0
  11. package/dist/guard/index.mjs.map +1 -1
  12. package/dist/guard/is-length-bounded-string.d.mts +164 -0
  13. package/dist/guard/is-length-bounded-string.d.mts.map +1 -0
  14. package/dist/guard/is-length-bounded-string.mjs +164 -0
  15. package/dist/guard/is-length-bounded-string.mjs.map +1 -0
  16. package/dist/index.mjs +1 -0
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/number/branded-types/int.d.mts +1 -1
  19. package/dist/number/branded-types/int16.d.mts +1 -1
  20. package/dist/number/branded-types/int32.d.mts +1 -1
  21. package/dist/number/branded-types/non-negative-int16.d.mts +1 -1
  22. package/dist/number/branded-types/non-negative-int32.d.mts +1 -1
  23. package/dist/number/branded-types/positive-int.d.mts +1 -1
  24. package/dist/number/branded-types/positive-int16.d.mts +1 -1
  25. package/dist/number/branded-types/positive-int32.d.mts +1 -1
  26. package/dist/number/branded-types/positive-safe-int.d.mts +1 -1
  27. package/dist/number/branded-types/positive-uint16.d.mts +1 -1
  28. package/dist/number/branded-types/positive-uint32.d.mts +1 -1
  29. package/dist/number/branded-types/safe-int.d.mts +1 -1
  30. package/dist/number/branded-types/safe-uint.d.mts +1 -1
  31. package/dist/number/branded-types/uint.d.mts +1 -1
  32. package/dist/number/branded-types/uint16.d.mts +1 -1
  33. package/dist/number/branded-types/uint32.d.mts +1 -1
  34. package/dist/number/refined-number-utils.d.mts.map +1 -1
  35. package/dist/number/refined-number-utils.mjs.map +1 -1
  36. package/dist/object/object.d.mts.map +1 -1
  37. package/dist/object/object.mjs.map +1 -1
  38. package/package.json +10 -10
  39. package/src/array/impl/array-utils-transformation.mts +1 -2
  40. package/src/array/impl/array-utils-transformation.test.mts +3 -36
  41. package/src/array/impl/array-utils-validation.test.mts +1 -3
  42. package/src/expect-type.mts +4 -5
  43. package/src/functional/ternary-result/ternary-result.mts +2 -6
  44. package/src/guard/index.mts +1 -0
  45. package/src/guard/is-length-bounded-string.mts +199 -0
  46. package/src/guard/is-length-bounded-string.test.mts +170 -0
  47. package/src/number/refined-number-utils.mts +1 -9
  48. 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
- | 'add'
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
 
@@ -224,11 +224,9 @@ export namespace Obj {
224
224
  const Keys extends readonly (keyof R)[],
225
225
  >(
226
226
  ...args:
227
- | readonly [record: R, keys: Keys]
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
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
648
- readonly [K in keyof B as {} extends Pick<B, K>
649
- ? K extends keyof A
650
- ? never
651
- : K
652
- : never]?: B[K];
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
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
656
- readonly [K in keyof B as {} extends Pick<B, K>
657
- ? K extends keyof A
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
- : never]?: K extends keyof A ? A[K] | B[K] : never;
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
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
664
- readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K>
665
- ? never
666
- : K]: A[K];
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
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
670
- readonly [K in Exclude<keyof A, keyof B> as {} extends Pick<A, K>
671
- ? K
672
- : never]?: A[K];
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
  {