ts-data-forge 4.1.0 → 5.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/json/json.d.mts +9 -3
- package/dist/json/json.d.mts.map +1 -1
- package/dist/json/json.mjs +6 -0
- package/dist/json/json.mjs.map +1 -1
- package/package.json +13 -13
- package/src/array/impl/array-utils-creation.test.mts +187 -74
- package/src/array/impl/array-utils-element-access.test.mts +19 -3
- package/src/array/impl/array-utils-iterators.test.mts +44 -24
- package/src/array/impl/array-utils-modification.test.mts +36 -33
- package/src/array/impl/array-utils-reducing-value.test.mts +47 -16
- package/src/array/impl/array-utils-search.test.mts +42 -9
- package/src/array/impl/array-utils-set-op.test.mts +54 -26
- package/src/array/impl/array-utils-size.test.mts +1 -0
- package/src/array/impl/array-utils-slice-clamped.test.mts +20 -11
- package/src/array/impl/array-utils-slicing.test.mts +27 -21
- package/src/array/impl/array-utils-transformation.test.mts +140 -92
- package/src/array/impl/array-utils-validation.test.mts +58 -10
- package/src/array/impl/array.test.mts +5 -5
- package/src/collections/imap-mapped.test.mts +63 -18
- package/src/collections/imap.test.mts +74 -26
- package/src/collections/iset-mapped.test.mts +81 -30
- package/src/collections/iset.test.mts +168 -68
- package/src/collections/queue.test.mts +32 -1
- package/src/collections/stack.test.mts +22 -8
- package/src/functional/match.test.mts +1 -1
- package/src/functional/optional.test.mts +61 -4
- package/src/functional/pipe.test.mts +10 -1
- package/src/functional/result.test.mts +127 -4
- package/src/functional/ternary-result.test.mts +34 -18
- package/src/guard/is-non-empty-string.test.mts +5 -2
- package/src/guard/is-non-null-object.test.mts +3 -5
- package/src/guard/is-primitive.test.mts +5 -3
- package/src/guard/is-record.test.mts +1 -1
- package/src/guard/is-type.test.mts +35 -20
- package/src/guard/key-is-in.test.mts +1 -1
- package/src/iterator/range.test.mts +22 -16
- package/src/json/json.mts +9 -3
- package/src/json/json.test.mts +140 -64
- package/src/number/branded-types/finite-number.test.mts +3 -2
- package/src/number/branded-types/int.test.mts +4 -3
- package/src/number/branded-types/int16.test.mts +9 -3
- package/src/number/branded-types/int32.test.mts +9 -3
- package/src/number/branded-types/non-negative-finite-number.test.mts +6 -4
- package/src/number/branded-types/non-negative-int16.test.mts +8 -3
- package/src/number/branded-types/non-negative-int32.test.mts +8 -3
- package/src/number/branded-types/non-zero-finite-number.test.mts +6 -3
- package/src/number/branded-types/non-zero-int.test.mts +6 -3
- package/src/number/branded-types/non-zero-int16.test.mts +9 -3
- package/src/number/branded-types/non-zero-int32.test.mts +9 -3
- package/src/number/branded-types/non-zero-safe-int.test.mts +10 -3
- package/src/number/branded-types/non-zero-uint16.test.mts +8 -3
- package/src/number/branded-types/non-zero-uint32.test.mts +8 -3
- package/src/number/branded-types/positive-finite-number.test.mts +7 -3
- package/src/number/branded-types/positive-int.test.mts +5 -3
- package/src/number/branded-types/positive-int16.test.mts +8 -3
- package/src/number/branded-types/positive-int32.test.mts +8 -3
- package/src/number/branded-types/positive-safe-int.test.mts +8 -3
- package/src/number/branded-types/positive-uint16.test.mts +8 -3
- package/src/number/branded-types/positive-uint32.test.mts +8 -3
- package/src/number/branded-types/safe-int.test.mts +8 -2
- package/src/number/branded-types/safe-uint.test.mts +8 -3
- package/src/number/branded-types/uint.test.mts +5 -3
- package/src/number/branded-types/uint16.test.mts +8 -3
- package/src/number/branded-types/uint32.test.mts +8 -3
- package/src/number/enum/int8.test.mts +8 -3
- package/src/number/enum/uint8.test.mts +6 -3
- package/src/number/num.test.mts +16 -2
- package/src/object/object.test.mts +26 -13
- package/src/others/cast-mutable.test.mts +10 -8
- package/src/others/cast-readonly.test.mts +9 -5
- package/src/others/if-then.test.mts +4 -1
- package/src/others/map-nullable.test.mts +28 -1
- package/src/others/memoize-function.test.mts +20 -17
- package/src/others/tuple.test.mts +3 -2
- package/src/others/unknown-to-string.test.mts +15 -2
- package/src/promise/promise.test.mts +6 -1
|
@@ -2,7 +2,7 @@ import { expectType } from '../expect-type.mjs';
|
|
|
2
2
|
import { Optional } from './optional/index.mjs';
|
|
3
3
|
import { TernaryResult } from './ternary-result/index.mjs';
|
|
4
4
|
|
|
5
|
-
describe('TernaryResult', () => {
|
|
5
|
+
describe('TernaryResult test', () => {
|
|
6
6
|
test('constructors and guards', () => {
|
|
7
7
|
const ok = TernaryResult.ok(1);
|
|
8
8
|
const warn = TernaryResult.warn(1, 'caution');
|
|
@@ -64,10 +64,12 @@ describe('TernaryResult', () => {
|
|
|
64
64
|
|
|
65
65
|
expect(TernaryResult.unwrapOk(okResult)).toBe(3);
|
|
66
66
|
expect(TernaryResult.isWarn(warnResult)).toBe(true);
|
|
67
|
+
|
|
67
68
|
if (TernaryResult.isWarn(warnResult)) {
|
|
68
69
|
expect(warnResult.value).toBe(3);
|
|
69
70
|
expect(warnResult.warning).toBe('slow');
|
|
70
71
|
}
|
|
72
|
+
|
|
71
73
|
expect(TernaryResult.unwrapErr(errResult)).toBe('bad');
|
|
72
74
|
});
|
|
73
75
|
|
|
@@ -93,24 +95,28 @@ describe('TernaryResult', () => {
|
|
|
93
95
|
|
|
94
96
|
expect(TernaryResult.unwrapOk(value)).toBe(2);
|
|
95
97
|
expect(TernaryResult.unwrapOk(warn)).toBe(4);
|
|
96
|
-
|
|
98
|
+
|
|
99
|
+
assert.deepStrictEqual(TernaryResult.unwrapWarn(warn), {
|
|
97
100
|
warning: 'heads up',
|
|
98
101
|
});
|
|
99
|
-
|
|
102
|
+
assert.deepStrictEqual(TernaryResult.unwrapErr(err), { message: 'boom' });
|
|
100
103
|
});
|
|
101
104
|
|
|
102
105
|
test('orElse keeps Ok and Warn variants', () => {
|
|
103
106
|
const fallback = TernaryResult.ok('fallback');
|
|
104
107
|
|
|
105
|
-
|
|
108
|
+
assert.deepStrictEqual(
|
|
106
109
|
TernaryResult.orElse(TernaryResult.ok('value'), fallback),
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
TernaryResult.ok('value'),
|
|
111
|
+
);
|
|
112
|
+
assert.deepStrictEqual(
|
|
109
113
|
TernaryResult.orElse(TernaryResult.warn('value', 'warn'), fallback),
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
TernaryResult.warn('value', 'warn'),
|
|
115
|
+
);
|
|
116
|
+
assert.deepStrictEqual(
|
|
112
117
|
TernaryResult.orElse(TernaryResult.err('err'), fallback),
|
|
113
|
-
|
|
118
|
+
fallback,
|
|
119
|
+
);
|
|
114
120
|
});
|
|
115
121
|
|
|
116
122
|
test('unwrap helpers', () => {
|
|
@@ -150,26 +156,32 @@ describe('TernaryResult', () => {
|
|
|
150
156
|
const warn = TernaryResult.warn('warn', 'warned');
|
|
151
157
|
const err = TernaryResult.err('err');
|
|
152
158
|
|
|
153
|
-
|
|
159
|
+
assert.deepStrictEqual(
|
|
160
|
+
TernaryResult.zip(ok, TernaryResult.ok(1)),
|
|
154
161
|
TernaryResult.ok(['x', 1] as const),
|
|
155
162
|
);
|
|
156
|
-
|
|
163
|
+
assert.deepStrictEqual(
|
|
164
|
+
TernaryResult.zip(ok, warn),
|
|
157
165
|
TernaryResult.warn(['x', 'warn'] as const, 'warned'),
|
|
158
166
|
);
|
|
159
|
-
|
|
167
|
+
assert.deepStrictEqual(
|
|
168
|
+
TernaryResult.zip(warn, ok),
|
|
160
169
|
TernaryResult.warn(['warn', 'x'] as const, 'warned'),
|
|
161
170
|
);
|
|
162
|
-
|
|
163
|
-
|
|
171
|
+
assert.deepStrictEqual(TernaryResult.zip(ok, err), err);
|
|
172
|
+
assert.deepStrictEqual(TernaryResult.zip(err, warn), err);
|
|
164
173
|
});
|
|
165
174
|
|
|
166
175
|
test('toOptional keeps only Ok values', () => {
|
|
167
|
-
|
|
176
|
+
assert.deepStrictEqual(
|
|
177
|
+
TernaryResult.toOptional(TernaryResult.ok(1)),
|
|
168
178
|
Optional.some(1),
|
|
169
179
|
);
|
|
170
|
-
|
|
180
|
+
assert.deepStrictEqual(
|
|
171
181
|
TernaryResult.toOptional(TernaryResult.warn(1, 'warn')),
|
|
172
|
-
|
|
182
|
+
Optional.some(1),
|
|
183
|
+
);
|
|
184
|
+
|
|
173
185
|
expect(TernaryResult.toOptional(TernaryResult.err('err'))).toBe(
|
|
174
186
|
Optional.none,
|
|
175
187
|
);
|
|
@@ -183,16 +195,20 @@ describe('TernaryResult', () => {
|
|
|
183
195
|
const rejected = await TernaryResult.fromPromise(
|
|
184
196
|
Promise.reject(new Error('bad')),
|
|
185
197
|
);
|
|
198
|
+
|
|
186
199
|
expect(TernaryResult.isErr(rejected)).toBe(true);
|
|
187
200
|
});
|
|
188
201
|
|
|
189
202
|
test('fromThrowable converts thrown values', () => {
|
|
190
|
-
|
|
203
|
+
assert.deepStrictEqual(
|
|
204
|
+
TernaryResult.fromThrowable(() => 5),
|
|
191
205
|
TernaryResult.ok(5),
|
|
192
206
|
);
|
|
207
|
+
|
|
193
208
|
const errorResult = TernaryResult.fromThrowable(() => {
|
|
194
209
|
throw new Error('boom');
|
|
195
210
|
});
|
|
211
|
+
|
|
196
212
|
expect(TernaryResult.isErr(errorResult)).toBe(true);
|
|
197
213
|
});
|
|
198
214
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectType } from '../expect-type.mjs';
|
|
2
2
|
import { isNonEmptyString } from './is-non-empty-string.mjs';
|
|
3
3
|
|
|
4
|
-
describe(
|
|
4
|
+
describe(isNonEmptyString, () => {
|
|
5
5
|
test('should return true for non-empty strings', () => {
|
|
6
6
|
expect(isNonEmptyString('hello')).toBe(true);
|
|
7
7
|
expect(isNonEmptyString('a')).toBe(true);
|
|
@@ -42,6 +42,7 @@ describe('isNonEmptyString', () => {
|
|
|
42
42
|
// @ts-expect-error Testing non-string types
|
|
43
43
|
if (isNonEmptyString(value)) {
|
|
44
44
|
expectType<typeof value, string>('=');
|
|
45
|
+
|
|
45
46
|
// TypeScript knows it's a string
|
|
46
47
|
expect(value.length).toBeGreaterThan(0);
|
|
47
48
|
expect(value.charAt(0)).toBe('t');
|
|
@@ -53,6 +54,7 @@ describe('isNonEmptyString', () => {
|
|
|
53
54
|
|
|
54
55
|
if (isNonEmptyString(maybeString)) {
|
|
55
56
|
expectType<typeof maybeString, string>('=');
|
|
57
|
+
|
|
56
58
|
expect(maybeString.toUpperCase()).toBe('HELLO');
|
|
57
59
|
}
|
|
58
60
|
});
|
|
@@ -71,7 +73,8 @@ describe('isNonEmptyString', () => {
|
|
|
71
73
|
|
|
72
74
|
// @ts-expect-error Testing non-string types
|
|
73
75
|
const nonEmptyStrings = mixed.filter(isNonEmptyString);
|
|
74
|
-
|
|
76
|
+
|
|
77
|
+
assert.deepStrictEqual(nonEmptyStrings, ['valid', 'another', 'third']);
|
|
75
78
|
});
|
|
76
79
|
|
|
77
80
|
test('should handle string edge cases', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectType } from '../expect-type.mjs';
|
|
2
2
|
import { isNonNullObject } from './is-non-null-object.mjs';
|
|
3
3
|
|
|
4
|
-
describe(
|
|
4
|
+
describe(isNonNullObject, () => {
|
|
5
5
|
test('should return true for plain objects', () => {
|
|
6
6
|
expect(isNonNullObject({})).toBe(true);
|
|
7
7
|
expect(isNonNullObject({ a: 1, b: 'test' })).toBe(true);
|
|
@@ -57,9 +57,7 @@ describe('isNonNullObject', () => {
|
|
|
57
57
|
const value: unknown = { test: true };
|
|
58
58
|
|
|
59
59
|
if (isNonNullObject(value)) {
|
|
60
|
-
expectType<typeof value,
|
|
61
|
-
// Can access object methods
|
|
62
|
-
expect(typeof value.toString).toBe('function');
|
|
60
|
+
expectType<typeof value, object>('=');
|
|
63
61
|
}
|
|
64
62
|
});
|
|
65
63
|
|
|
@@ -85,6 +83,6 @@ describe('isNonNullObject', () => {
|
|
|
85
83
|
|
|
86
84
|
const objects = mixed.filter(isNonNullObject);
|
|
87
85
|
|
|
88
|
-
|
|
86
|
+
assert.deepStrictEqual(objects, [{ a: 1 }, []]);
|
|
89
87
|
});
|
|
90
88
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { expectType } from '../expect-type.mjs';
|
|
2
2
|
import { isPrimitive } from './is-primitive.mjs';
|
|
3
|
+
import { isSymbol } from './is-type.mjs';
|
|
3
4
|
|
|
4
|
-
describe(
|
|
5
|
+
describe(isPrimitive, () => {
|
|
5
6
|
test('should return true for string primitives', () => {
|
|
6
7
|
expect(isPrimitive('hello')).toBe(true);
|
|
7
8
|
expect(isPrimitive('')).toBe(true);
|
|
@@ -95,8 +96,9 @@ describe('isPrimitive', () => {
|
|
|
95
96
|
expect(primitives[2]).toBe(true);
|
|
96
97
|
expect(primitives[3]).toBeNull();
|
|
97
98
|
expect(primitives[4]).toBeUndefined();
|
|
98
|
-
expect(typeof primitives[5]).toBe('symbol');
|
|
99
99
|
|
|
100
|
-
expect(
|
|
100
|
+
expect(isSymbol(primitives[5])).toBe(true);
|
|
101
|
+
|
|
102
|
+
assert.deepStrictEqual(nonPrimitives, [{}, []]);
|
|
101
103
|
});
|
|
102
104
|
});
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
isUndefined,
|
|
19
19
|
} from './is-type.mjs';
|
|
20
20
|
|
|
21
|
-
describe(
|
|
21
|
+
describe(isUndefined, () => {
|
|
22
22
|
test('should return true for undefined', () => {
|
|
23
23
|
expect(isUndefined(undefined)).toBe(true);
|
|
24
24
|
});
|
|
@@ -39,7 +39,7 @@ describe('isUndefined', () => {
|
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
-
describe(
|
|
42
|
+
describe(isNotUndefined, () => {
|
|
43
43
|
test('should return false for undefined', () => {
|
|
44
44
|
expect(isNotUndefined(undefined)).toBe(false);
|
|
45
45
|
});
|
|
@@ -59,7 +59,7 @@ describe('isNotUndefined', () => {
|
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
describe(
|
|
62
|
+
describe(isNull, () => {
|
|
63
63
|
test('should return true for null', () => {
|
|
64
64
|
expect(isNull(null)).toBe(true);
|
|
65
65
|
});
|
|
@@ -80,7 +80,7 @@ describe('isNull', () => {
|
|
|
80
80
|
});
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
describe(
|
|
83
|
+
describe(isNotNull, () => {
|
|
84
84
|
test('should return false for null', () => {
|
|
85
85
|
expect(isNotNull(null)).toBe(false);
|
|
86
86
|
});
|
|
@@ -99,7 +99,7 @@ describe('isNotNull', () => {
|
|
|
99
99
|
});
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
describe(
|
|
102
|
+
describe(isString, () => {
|
|
103
103
|
test('should return true for strings', () => {
|
|
104
104
|
expect(isString('')).toBe(true);
|
|
105
105
|
expect(isString('hello')).toBe(true);
|
|
@@ -120,12 +120,13 @@ describe('isString', () => {
|
|
|
120
120
|
const value: unknown = 'test';
|
|
121
121
|
if (isString(value)) {
|
|
122
122
|
expectType<typeof value, string>('=');
|
|
123
|
+
|
|
123
124
|
expect(value).toHaveLength(4);
|
|
124
125
|
}
|
|
125
126
|
});
|
|
126
127
|
});
|
|
127
128
|
|
|
128
|
-
describe(
|
|
129
|
+
describe(isNumber, () => {
|
|
129
130
|
test('should return true for numbers', () => {
|
|
130
131
|
expect(isNumber(0)).toBe(true);
|
|
131
132
|
expect(isNumber(42)).toBe(true);
|
|
@@ -148,12 +149,13 @@ describe('isNumber', () => {
|
|
|
148
149
|
const value: unknown = 42;
|
|
149
150
|
if (isNumber(value)) {
|
|
150
151
|
expectType<typeof value, number>('=');
|
|
152
|
+
|
|
151
153
|
expect(value + 1).toBe(43);
|
|
152
154
|
}
|
|
153
155
|
});
|
|
154
156
|
});
|
|
155
157
|
|
|
156
|
-
describe(
|
|
158
|
+
describe(isBigint, () => {
|
|
157
159
|
test('should return true for bigints', () => {
|
|
158
160
|
expect(isBigint(0n)).toBe(true);
|
|
159
161
|
expect(isBigint(123n)).toBe(true);
|
|
@@ -171,12 +173,13 @@ describe('isBigint', () => {
|
|
|
171
173
|
const value: unknown = 123n;
|
|
172
174
|
if (isBigint(value)) {
|
|
173
175
|
expectType<typeof value, bigint>('=');
|
|
176
|
+
|
|
174
177
|
expect(value + 1n).toBe(124n);
|
|
175
178
|
}
|
|
176
179
|
});
|
|
177
180
|
});
|
|
178
181
|
|
|
179
|
-
describe(
|
|
182
|
+
describe(isBoolean, () => {
|
|
180
183
|
test('should return true for booleans', () => {
|
|
181
184
|
expect(isBoolean(true)).toBe(true);
|
|
182
185
|
expect(isBoolean(false)).toBe(true);
|
|
@@ -195,12 +198,13 @@ describe('isBoolean', () => {
|
|
|
195
198
|
const value: unknown = true;
|
|
196
199
|
if (isBoolean(value)) {
|
|
197
200
|
expectType<typeof value, boolean>('=');
|
|
201
|
+
|
|
198
202
|
expect(!value).toBe(false);
|
|
199
203
|
}
|
|
200
204
|
});
|
|
201
205
|
});
|
|
202
206
|
|
|
203
|
-
describe(
|
|
207
|
+
describe(isSymbol, () => {
|
|
204
208
|
test('should return true for symbols', () => {
|
|
205
209
|
expect(isSymbol(Symbol())).toBe(true);
|
|
206
210
|
expect(isSymbol(Symbol('test'))).toBe(true);
|
|
@@ -217,12 +221,13 @@ describe('isSymbol', () => {
|
|
|
217
221
|
const value: unknown = Symbol('test');
|
|
218
222
|
if (isSymbol(value)) {
|
|
219
223
|
expectType<typeof value, symbol>('=');
|
|
224
|
+
|
|
220
225
|
expect(value.toString()).toContain('Symbol');
|
|
221
226
|
}
|
|
222
227
|
});
|
|
223
228
|
});
|
|
224
229
|
|
|
225
|
-
describe(
|
|
230
|
+
describe(isNotBoolean, () => {
|
|
226
231
|
test('should return false for boolean values', () => {
|
|
227
232
|
expect(isNotBoolean(true)).toBe(false);
|
|
228
233
|
expect(isNotBoolean(false)).toBe(false);
|
|
@@ -243,13 +248,14 @@ describe('isNotBoolean', () => {
|
|
|
243
248
|
const value: string | number | boolean = 'test';
|
|
244
249
|
if (isNotBoolean(value)) {
|
|
245
250
|
expectType<typeof value, string | number>('<=');
|
|
251
|
+
|
|
246
252
|
// Should not have boolean methods
|
|
247
253
|
expect(typeof value === 'string' || typeof value === 'number').toBe(true);
|
|
248
254
|
}
|
|
249
255
|
});
|
|
250
256
|
});
|
|
251
257
|
|
|
252
|
-
describe(
|
|
258
|
+
describe(isNotNumber, () => {
|
|
253
259
|
test('should return false for number values', () => {
|
|
254
260
|
expect(isNotNumber(0)).toBe(false);
|
|
255
261
|
expect(isNotNumber(42)).toBe(false);
|
|
@@ -275,6 +281,7 @@ describe('isNotNumber', () => {
|
|
|
275
281
|
const value: string | number | boolean = 'test';
|
|
276
282
|
if (isNotNumber(value)) {
|
|
277
283
|
expectType<typeof value, string | boolean>('<=');
|
|
284
|
+
|
|
278
285
|
expect(typeof value === 'string' || typeof value === 'boolean').toBe(
|
|
279
286
|
true,
|
|
280
287
|
);
|
|
@@ -282,7 +289,7 @@ describe('isNotNumber', () => {
|
|
|
282
289
|
});
|
|
283
290
|
});
|
|
284
291
|
|
|
285
|
-
describe(
|
|
292
|
+
describe(isNotBigint, () => {
|
|
286
293
|
test('should return false for bigint values', () => {
|
|
287
294
|
expect(isNotBigint(0n)).toBe(false);
|
|
288
295
|
expect(isNotBigint(123n)).toBe(false);
|
|
@@ -304,12 +311,13 @@ describe('isNotBigint', () => {
|
|
|
304
311
|
const value: number | bigint = 123;
|
|
305
312
|
if (isNotBigint(value)) {
|
|
306
313
|
expectType<typeof value, number>('<=');
|
|
307
|
-
|
|
314
|
+
|
|
315
|
+
expectTypeOf(value).toBeNumber();
|
|
308
316
|
}
|
|
309
317
|
});
|
|
310
318
|
});
|
|
311
319
|
|
|
312
|
-
describe(
|
|
320
|
+
describe(isNotString, () => {
|
|
313
321
|
test('should return false for string values', () => {
|
|
314
322
|
expect(isNotString('')).toBe(false);
|
|
315
323
|
expect(isNotString('hello')).toBe(false);
|
|
@@ -333,6 +341,7 @@ describe('isNotString', () => {
|
|
|
333
341
|
const value: string | number | boolean = 42;
|
|
334
342
|
if (isNotString(value)) {
|
|
335
343
|
expectType<typeof value, number | boolean>('<=');
|
|
344
|
+
|
|
336
345
|
expect(typeof value === 'number' || typeof value === 'boolean').toBe(
|
|
337
346
|
true,
|
|
338
347
|
);
|
|
@@ -340,7 +349,7 @@ describe('isNotString', () => {
|
|
|
340
349
|
});
|
|
341
350
|
});
|
|
342
351
|
|
|
343
|
-
describe(
|
|
352
|
+
describe(isNotSymbol, () => {
|
|
344
353
|
test('should return false for symbol values', () => {
|
|
345
354
|
expect(isNotSymbol(Symbol())).toBe(false);
|
|
346
355
|
expect(isNotSymbol(Symbol('test'))).toBe(false);
|
|
@@ -363,12 +372,13 @@ describe('isNotSymbol', () => {
|
|
|
363
372
|
const value: string | number | symbol = 'test';
|
|
364
373
|
if (isNotSymbol(value)) {
|
|
365
374
|
expectType<typeof value, string | number>('<=');
|
|
375
|
+
|
|
366
376
|
expect(typeof value === 'string' || typeof value === 'number').toBe(true);
|
|
367
377
|
}
|
|
368
378
|
});
|
|
369
379
|
});
|
|
370
380
|
|
|
371
|
-
describe(
|
|
381
|
+
describe(isNullish, () => {
|
|
372
382
|
test('should return true for null and undefined', () => {
|
|
373
383
|
expect(isNullish(null)).toBe(true);
|
|
374
384
|
expect(isNullish(undefined)).toBe(true);
|
|
@@ -389,6 +399,7 @@ describe('isNullish', () => {
|
|
|
389
399
|
const value: string | null | undefined = null;
|
|
390
400
|
if (isNullish(value)) {
|
|
391
401
|
expectType<typeof value, null | undefined>('<=');
|
|
402
|
+
|
|
392
403
|
// Value is guaranteed to be null or undefined in this branch
|
|
393
404
|
expect(true).toBe(true);
|
|
394
405
|
}
|
|
@@ -401,7 +412,7 @@ describe('isNullish', () => {
|
|
|
401
412
|
});
|
|
402
413
|
});
|
|
403
414
|
|
|
404
|
-
describe(
|
|
415
|
+
describe(isNonNullish, () => {
|
|
405
416
|
test('should return false for null and undefined', () => {
|
|
406
417
|
expect(isNonNullish(null)).toBe(false);
|
|
407
418
|
expect(isNonNullish(undefined)).toBe(false);
|
|
@@ -424,6 +435,7 @@ describe('isNonNullish', () => {
|
|
|
424
435
|
const value: string | null | undefined = 'test';
|
|
425
436
|
if (isNonNullish(value)) {
|
|
426
437
|
expectType<typeof value, string>('<=');
|
|
438
|
+
|
|
427
439
|
expect(value).toHaveLength(4);
|
|
428
440
|
}
|
|
429
441
|
});
|
|
@@ -441,7 +453,8 @@ describe('isNonNullish', () => {
|
|
|
441
453
|
expectType<typeof definedItems, string[]>('<=');
|
|
442
454
|
|
|
443
455
|
expect(definedItems).toHaveLength(3);
|
|
444
|
-
|
|
456
|
+
|
|
457
|
+
assert.deepStrictEqual(definedItems, ['hello', 'world', 'test']);
|
|
445
458
|
});
|
|
446
459
|
|
|
447
460
|
test('should handle complex union types', () => {
|
|
@@ -450,6 +463,7 @@ describe('isNonNullish', () => {
|
|
|
450
463
|
|
|
451
464
|
if (isNonNullish(value)) {
|
|
452
465
|
expectType<typeof value, string | number | boolean>('<=');
|
|
466
|
+
|
|
453
467
|
// Value is guaranteed to be non-nullish in this branch
|
|
454
468
|
expect(true).toBe(true);
|
|
455
469
|
}
|
|
@@ -462,7 +476,8 @@ describe('type guard behavior in complex scenarios', () => {
|
|
|
462
476
|
|
|
463
477
|
if (isNonNullish(value) && isNotBoolean(value) && isNotNumber(value)) {
|
|
464
478
|
expectType<typeof value, string>('<=');
|
|
465
|
-
|
|
479
|
+
|
|
480
|
+
expectTypeOf(value).toBeString();
|
|
466
481
|
}
|
|
467
482
|
});
|
|
468
483
|
|
|
@@ -487,6 +502,6 @@ describe('type guard behavior in complex scenarios', () => {
|
|
|
487
502
|
const strings = nonBooleans.filter(isNotNumber);
|
|
488
503
|
expectType<typeof strings, string[]>('<=');
|
|
489
504
|
|
|
490
|
-
|
|
505
|
+
assert.deepStrictEqual(strings, ['hello', 'world']);
|
|
491
506
|
});
|
|
492
507
|
});
|
|
@@ -5,7 +5,7 @@ const f = <Key extends string, V, KeySub extends Key>(
|
|
|
5
5
|
obj: ReadonlyRecord<KeySub, V>,
|
|
6
6
|
): V | undefined => (keyIsIn(key, obj) ? obj[key] : undefined);
|
|
7
7
|
|
|
8
|
-
describe(
|
|
8
|
+
describe(keyIsIn, () => {
|
|
9
9
|
f('a' as 'a' | 'b' | 'c', { a: 0, b: 1 });
|
|
10
10
|
|
|
11
11
|
test('', () => {
|
|
@@ -1,46 +1,52 @@
|
|
|
1
1
|
import { range } from './range.mjs';
|
|
2
2
|
|
|
3
|
-
describe(
|
|
3
|
+
describe(range, () => {
|
|
4
4
|
test('range(0, 10)', () => {
|
|
5
|
-
|
|
6
|
-
0,
|
|
7
|
-
|
|
5
|
+
assert.deepStrictEqual(
|
|
6
|
+
Array.from(range(0, 10)),
|
|
7
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
8
|
+
);
|
|
8
9
|
});
|
|
9
10
|
|
|
10
11
|
test('range(10)', () => {
|
|
11
|
-
|
|
12
|
+
assert.deepStrictEqual(
|
|
13
|
+
Array.from(range(10)),
|
|
14
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
15
|
+
);
|
|
12
16
|
});
|
|
13
17
|
|
|
14
18
|
test('range(0)', () => {
|
|
15
|
-
|
|
19
|
+
assert.deepStrictEqual(Array.from(range(0)), []);
|
|
16
20
|
});
|
|
17
21
|
|
|
18
22
|
test('range(-1)', () => {
|
|
19
23
|
// @ts-expect-error negative end is not allowed
|
|
20
|
-
|
|
24
|
+
assert.deepStrictEqual(Array.from(range(-1)), []);
|
|
21
25
|
});
|
|
22
26
|
|
|
23
27
|
test('range(10, 0, -1)', () => {
|
|
24
|
-
|
|
25
|
-
10,
|
|
26
|
-
|
|
28
|
+
assert.deepStrictEqual(
|
|
29
|
+
Array.from(range(10, 0, -1)),
|
|
30
|
+
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
|
|
31
|
+
);
|
|
27
32
|
});
|
|
28
33
|
|
|
29
34
|
test('range(0, -10, -1)', () => {
|
|
30
|
-
|
|
31
|
-
0, -
|
|
32
|
-
|
|
35
|
+
assert.deepStrictEqual(
|
|
36
|
+
Array.from(range(0, -10, -1)),
|
|
37
|
+
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9],
|
|
38
|
+
);
|
|
33
39
|
});
|
|
34
40
|
|
|
35
41
|
test('range(0, 0)', () => {
|
|
36
|
-
|
|
42
|
+
assert.deepStrictEqual(Array.from(range(0, 0)), []);
|
|
37
43
|
});
|
|
38
44
|
|
|
39
45
|
test('range(0, 11, 2)', () => {
|
|
40
|
-
|
|
46
|
+
assert.deepStrictEqual(Array.from(range(0, 11, 2)), [0, 2, 4, 6, 8, 10]);
|
|
41
47
|
});
|
|
42
48
|
|
|
43
49
|
test('range(1, 12, 2)', () => {
|
|
44
|
-
|
|
50
|
+
assert.deepStrictEqual(Array.from(range(1, 12, 2)), [1, 3, 5, 7, 9, 11]);
|
|
45
51
|
});
|
|
46
52
|
});
|
package/src/json/json.mts
CHANGED
|
@@ -108,6 +108,8 @@ export namespace Json {
|
|
|
108
108
|
*
|
|
109
109
|
* assert.ok(Result.isOk(filtered));
|
|
110
110
|
* if (Result.isOk(filtered)) {
|
|
111
|
+
* assert(isString(filtered.value));
|
|
112
|
+
*
|
|
111
113
|
* assert.ok(!filtered.value.includes('age'));
|
|
112
114
|
* }
|
|
113
115
|
* ```
|
|
@@ -136,7 +138,7 @@ export namespace Json {
|
|
|
136
138
|
value: unknown,
|
|
137
139
|
replacer?: (this: unknown, key: string, val: unknown) => unknown,
|
|
138
140
|
space?: UintRangeInclusive<1, 10> | string,
|
|
139
|
-
): Result<string, string> => {
|
|
141
|
+
): Result<string | undefined, string> => {
|
|
140
142
|
try {
|
|
141
143
|
return Result.ok(JSON.stringify(value, replacer, space));
|
|
142
144
|
} catch (error) {
|
|
@@ -170,6 +172,8 @@ export namespace Json {
|
|
|
170
172
|
*
|
|
171
173
|
* assert.ok(Result.isOk(safeJson));
|
|
172
174
|
* if (Result.isOk(safeJson)) {
|
|
175
|
+
* assert(isString(safeJson.value));
|
|
176
|
+
*
|
|
173
177
|
* const parsed: unknown = JSON.parse(safeJson.value);
|
|
174
178
|
* assert.deepStrictEqual(parsed, {
|
|
175
179
|
* id: 1,
|
|
@@ -207,7 +211,7 @@ export namespace Json {
|
|
|
207
211
|
value: unknown,
|
|
208
212
|
propertiesToBeSelected?: readonly (number | string)[],
|
|
209
213
|
space?: UintRangeInclusive<1, 10> | string,
|
|
210
|
-
): Result<string, string> => {
|
|
214
|
+
): Result<string | undefined, string> => {
|
|
211
215
|
try {
|
|
212
216
|
return Result.ok(
|
|
213
217
|
JSON.stringify(value, castMutable(propertiesToBeSelected), space),
|
|
@@ -257,6 +261,8 @@ export namespace Json {
|
|
|
257
261
|
* const formatted = Json.stringifySortedKey(unorderedData, 2);
|
|
258
262
|
* assert.ok(Result.isOk(formatted));
|
|
259
263
|
* if (Result.isOk(formatted)) {
|
|
264
|
+
* assert(isString(formatted.value));
|
|
265
|
+
*
|
|
260
266
|
* // Check that keys are in order (first key should be "apple")
|
|
261
267
|
* assert.ok(
|
|
262
268
|
* formatted.value.indexOf('"apple"') < formatted.value.indexOf('"mango"'),
|
|
@@ -288,7 +294,7 @@ export namespace Json {
|
|
|
288
294
|
export const stringifySortedKey = (
|
|
289
295
|
value: UnknownRecord,
|
|
290
296
|
space?: UintRangeInclusive<1, 10> | string,
|
|
291
|
-
): Result<string, string> => {
|
|
297
|
+
): Result<string | undefined, string> => {
|
|
292
298
|
const allKeys = pipe(keysDeep(value))
|
|
293
299
|
.map((keys) => Arr.uniq(keys))
|
|
294
300
|
.map((ks) => ks.toSorted()).value;
|