ts-fortress 2.2.1 → 2.3.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 +135 -0
- package/dist/array/array-of-length.d.mts.map +1 -1
- package/dist/array/array-of-length.mjs +8 -6
- package/dist/array/array-of-length.mjs.map +1 -1
- package/dist/array/array.d.mts.map +1 -1
- package/dist/array/array.mjs +8 -6
- package/dist/array/array.mjs.map +1 -1
- package/dist/array/non-empty-array.d.mts.map +1 -1
- package/dist/array/non-empty-array.mjs +8 -6
- package/dist/array/non-empty-array.mjs.map +1 -1
- package/dist/array/tuple.d.mts.map +1 -1
- package/dist/array/tuple.mjs +8 -6
- package/dist/array/tuple.mjs.map +1 -1
- package/dist/compose/index.d.mts +1 -0
- package/dist/compose/index.d.mts.map +1 -1
- package/dist/compose/index.mjs +1 -0
- package/dist/compose/index.mjs.map +1 -1
- package/dist/compose/intersection.d.mts.map +1 -1
- package/dist/compose/intersection.mjs +10 -10
- package/dist/compose/intersection.mjs.map +1 -1
- package/dist/compose/merge-records.d.mts.map +1 -1
- package/dist/compose/merge-records.mjs +10 -10
- package/dist/compose/merge-records.mjs.map +1 -1
- package/dist/compose/recursion.d.mts +5 -0
- package/dist/compose/recursion.d.mts.map +1 -0
- package/dist/compose/recursion.mjs +38 -0
- package/dist/compose/recursion.mjs.map +1 -0
- package/dist/compose/union.d.mts.map +1 -1
- package/dist/compose/union.mjs.map +1 -1
- package/dist/enum/enum.d.mts.map +1 -1
- package/dist/enum/enum.mjs.map +1 -1
- package/dist/enum/uint-range.d.mts.map +1 -1
- package/dist/enum/uint-range.mjs.map +1 -1
- package/dist/index.d.mts +0 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/record/key-value-record.d.mts.map +1 -1
- package/dist/record/key-value-record.mjs +21 -24
- package/dist/record/key-value-record.mjs.map +1 -1
- package/dist/record/omit.d.mts.map +1 -1
- package/dist/record/omit.mjs +3 -2
- package/dist/record/omit.mjs.map +1 -1
- package/dist/record/partial.d.mts.map +1 -1
- package/dist/record/partial.mjs +2 -2
- package/dist/record/partial.mjs.map +1 -1
- package/dist/record/pick.d.mts.map +1 -1
- package/dist/record/pick.mjs +2 -2
- package/dist/record/pick.mjs.map +1 -1
- package/dist/record/record.d.mts.map +1 -1
- package/dist/record/record.mjs +23 -21
- package/dist/record/record.mjs.map +1 -1
- package/dist/type.d.mts +1 -1
- package/dist/type.d.mts.map +1 -1
- package/dist/utils/create-assert-fn.mjs +1 -1
- package/dist/utils/create-cast-fn.mjs +1 -1
- package/dist/utils/create-primitive-type.mjs +1 -1
- package/dist/utils/index.d.mts +1 -0
- package/dist/utils/index.d.mts.map +1 -1
- package/dist/utils/index.mjs +1 -0
- package/dist/utils/index.mjs.map +1 -1
- package/dist/utils/validation-error.d.mts.map +1 -0
- package/dist/utils/validation-error.mjs.map +1 -0
- package/package.json +4 -2
- package/src/array/array-of-length.mts +12 -7
- package/src/array/array-of-length.test.mts +10 -1
- package/src/array/array.mts +12 -7
- package/src/array/array.test.mts +10 -1
- package/src/array/non-empty-array.mts +11 -7
- package/src/array/non-empty-array.test.mts +10 -1
- package/src/array/tuple.mts +11 -9
- package/src/array/tuple.test.mts +14 -1
- package/src/branded/brand.mts +2 -2
- package/src/branded/number/finite-number.test.mts +10 -1
- package/src/branded/number/int.test.mts +10 -1
- package/src/branded/number/int16.test.mts +10 -1
- package/src/branded/number/int32.test.mts +10 -1
- package/src/branded/number/non-negative-finite-number.test.mts +10 -1
- package/src/branded/number/non-zero-finite-number.test.mts +10 -1
- package/src/branded/number/non-zero-int.test.mts +10 -1
- package/src/branded/number/non-zero-safe-int.test.mts +10 -1
- package/src/branded/number/positive-finite-number.test.mts +10 -1
- package/src/branded/number/positive-int.test.mts +10 -1
- package/src/branded/number/positive-safe-int.test.mts +10 -1
- package/src/branded/number/safe-int.test.mts +10 -1
- package/src/branded/number/safe-uint.test.mts +10 -1
- package/src/branded/number/uint.test.mts +10 -1
- package/src/branded/number/uint16.test.mts +10 -1
- package/src/branded/number/uint32.test.mts +10 -1
- package/src/branded/simple-branded-number.test.mts +19 -1
- package/src/branded/simple-branded-string.test.mts +19 -1
- package/src/compose/index.mts +1 -0
- package/src/compose/intersection.mts +23 -19
- package/src/compose/intersection.test.mts +28 -1
- package/src/compose/merge-records.mts +22 -19
- package/src/compose/merge-records.test.mts +10 -1
- package/src/compose/recursion.mts +49 -0
- package/src/compose/recursion.test.mts +234 -0
- package/src/compose/union.mts +6 -2
- package/src/compose/union.test.mts +10 -1
- package/src/enum/enum.mts +6 -2
- package/src/enum/enum.test.mts +10 -1
- package/src/enum/uint-range.mts +6 -2
- package/src/enum/uint-range.test.mts +10 -1
- package/src/index.mts +0 -1
- package/src/primitives/bigint.test.mts +19 -1
- package/src/primitives/boolean.test.mts +28 -1
- package/src/primitives/null.test.mts +9 -0
- package/src/primitives/number.test.mts +18 -0
- package/src/primitives/string.test.mts +18 -0
- package/src/primitives/symbol.test.mts +10 -1
- package/src/primitives/undefined.test.mts +9 -0
- package/src/record/key-value-record.mts +34 -36
- package/src/record/key-value-record.test.mts +14 -1
- package/src/record/keyof.test.mts +10 -1
- package/src/record/omit.mts +8 -5
- package/src/record/omit.test.mts +46 -1
- package/src/record/partial.mts +7 -5
- package/src/record/partial.test.mts +71 -1
- package/src/record/pick.mts +7 -5
- package/src/record/pick.test.mts +46 -1
- package/src/record/record-allow-excess-properties.test.mts +28 -1
- package/src/record/record-strict-composition-simple.test.mts +38 -0
- package/src/record/record-strict-composition.test.mts +71 -0
- package/src/record/record.mts +30 -29
- package/src/record/record.test.mts +26 -1
- package/src/record/strict-record.test.mts +10 -1
- package/src/type.mts +1 -1
- package/src/utils/create-assert-fn.mts +1 -1
- package/src/utils/create-cast-fn.mts +1 -1
- package/src/utils/create-primitive-type.mts +1 -1
- package/src/utils/index.mts +1 -0
- package/dist/validation-error.d.mts.map +0 -1
- package/dist/validation-error.mjs.map +0 -1
- package/src/combination.test.mts +0 -544
- /package/dist/{validation-error.d.mts → utils/validation-error.d.mts} +0 -0
- /package/dist/{validation-error.mjs → utils/validation-error.mjs} +0 -0
- /package/src/{validation-error.mts → utils/validation-error.mts} +0 -0
- /package/src/{validation-error.test.mts → utils/validation-error.test.mts} +0 -0
|
@@ -175,5 +175,14 @@ describe('undefinedType', () => {
|
|
|
175
175
|
]);
|
|
176
176
|
}
|
|
177
177
|
});
|
|
178
|
+
|
|
179
|
+
test('validate returns input as-is for OK cases', () => {
|
|
180
|
+
const input = undefined;
|
|
181
|
+
const result = undefinedType.validate(input);
|
|
182
|
+
expect(Result.isOk(result)).toBe(true);
|
|
183
|
+
if (Result.isOk(result)) {
|
|
184
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
185
|
+
}
|
|
186
|
+
});
|
|
178
187
|
});
|
|
179
188
|
});
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { isRecord, Result } from 'ts-data-forge';
|
|
1
|
+
import { Arr, isRecord, Result } from 'ts-data-forge';
|
|
2
2
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
3
|
-
import { createAssertFn, createCastFn, createIsFn } from '../utils/index.mjs';
|
|
4
3
|
import {
|
|
4
|
+
createAssertFn,
|
|
5
|
+
createCastFn,
|
|
6
|
+
createIsFn,
|
|
5
7
|
createPrimitiveValidationError,
|
|
6
8
|
prependPathToValidationErrors,
|
|
7
9
|
type ValidationError,
|
|
8
10
|
type ValidationErrorWithMessage,
|
|
9
|
-
} from '../
|
|
11
|
+
} from '../utils/index.mjs';
|
|
10
12
|
|
|
11
13
|
type RecordResultType<
|
|
12
14
|
K extends Type<string>,
|
|
@@ -36,43 +38,39 @@ export const keyValueRecord = <K extends Type<string>, V extends Type<unknown>>(
|
|
|
36
38
|
]);
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
const errors: readonly ValidationError[] =
|
|
40
|
-
([k, v])
|
|
41
|
-
|
|
41
|
+
const errors: readonly ValidationError[] = Arr.generate(function* () {
|
|
42
|
+
for (const [k, v] of Object.entries(a)) {
|
|
43
|
+
{
|
|
42
44
|
const res = keyType.validate(k);
|
|
43
|
-
return Result.isErr(res)
|
|
44
|
-
? [
|
|
45
|
-
{
|
|
46
|
-
path: [],
|
|
47
|
-
actualValue: k,
|
|
48
|
-
expectedType: typeName,
|
|
49
|
-
message: `The key of the record is expected to be <${keyType.typeName}>`,
|
|
50
|
-
typeName,
|
|
51
|
-
} satisfies ValidationErrorWithMessage,
|
|
52
|
-
...res.value,
|
|
53
|
-
]
|
|
54
|
-
: [];
|
|
55
|
-
})();
|
|
56
45
|
|
|
57
|
-
|
|
46
|
+
if (Result.isErr(res)) {
|
|
47
|
+
yield {
|
|
48
|
+
path: [],
|
|
49
|
+
actualValue: k,
|
|
50
|
+
expectedType: typeName,
|
|
51
|
+
message: `The key of the record is expected to be <${keyType.typeName}>`,
|
|
52
|
+
typeName,
|
|
53
|
+
} satisfies ValidationErrorWithMessage;
|
|
54
|
+
|
|
55
|
+
yield* res.value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
{
|
|
58
59
|
const res = valueType.validate(v);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
} satisfies ValidationErrorWithMessage,
|
|
68
|
-
...prependPathToValidationErrors(res.value, k),
|
|
69
|
-
]
|
|
70
|
-
: [];
|
|
71
|
-
})();
|
|
60
|
+
if (Result.isErr(res)) {
|
|
61
|
+
yield {
|
|
62
|
+
path: [],
|
|
63
|
+
actualValue: v,
|
|
64
|
+
expectedType: typeName,
|
|
65
|
+
message: `The value of the record is expected to be <${valueType.typeName}>`,
|
|
66
|
+
typeName,
|
|
67
|
+
} satisfies ValidationErrorWithMessage;
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
yield* prependPathToValidationErrors(res.value, k);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
76
74
|
|
|
77
75
|
if (errors.length > 0) {
|
|
78
76
|
return Result.err(errors);
|
|
@@ -4,7 +4,7 @@ import { type TypeOf } from '../type.mjs';
|
|
|
4
4
|
import {
|
|
5
5
|
type ValidationError,
|
|
6
6
|
validationErrorsToMessages,
|
|
7
|
-
} from '../
|
|
7
|
+
} from '../utils/index.mjs';
|
|
8
8
|
import { keyValueRecord } from './key-value-record.mjs';
|
|
9
9
|
|
|
10
10
|
describe('keyValueRecord', () => {
|
|
@@ -74,6 +74,19 @@ describe('keyValueRecord', () => {
|
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
+
test('validate returns input as-is for OK cases', () => {
|
|
78
|
+
const input: UnknownRecord = {
|
|
79
|
+
year: 2000,
|
|
80
|
+
month: 12,
|
|
81
|
+
date: 25,
|
|
82
|
+
};
|
|
83
|
+
const result = strNumRecord.validate(input);
|
|
84
|
+
expect(Result.isOk(result)).toBe(true);
|
|
85
|
+
if (Result.isOk(result)) {
|
|
86
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
77
90
|
test('falsy case', () => {
|
|
78
91
|
const x: UnknownRecord = {
|
|
79
92
|
year: 2000,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectType, Result } from 'ts-data-forge';
|
|
2
2
|
import { number } from '../primitives/index.mjs';
|
|
3
3
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
4
|
-
import { validationErrorsToMessages } from '../
|
|
4
|
+
import { validationErrorsToMessages } from '../utils/index.mjs';
|
|
5
5
|
import { keyof } from './keyof.mjs';
|
|
6
6
|
import { record } from './record.mjs';
|
|
7
7
|
|
|
@@ -61,6 +61,15 @@ describe('keyof', () => {
|
|
|
61
61
|
}
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
test('validate returns input as-is for OK cases', () => {
|
|
65
|
+
const input = 'year';
|
|
66
|
+
const result = ymdKey.validate(input);
|
|
67
|
+
expect(Result.isOk(result)).toBe(true);
|
|
68
|
+
if (Result.isOk(result)) {
|
|
69
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
64
73
|
test('falsy case', () => {
|
|
65
74
|
const x: unknown = 'minutes';
|
|
66
75
|
|
package/src/record/omit.mts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { expectType, isRecord, Obj, Result } from 'ts-data-forge';
|
|
2
2
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
createAssertFn,
|
|
5
|
+
createCastFn,
|
|
6
|
+
createIsFn,
|
|
7
|
+
createPrimitiveValidationError,
|
|
8
|
+
} from '../utils/index.mjs';
|
|
5
9
|
|
|
6
10
|
/** Creates a record type with keys omitted. */
|
|
7
11
|
export const omit = <
|
|
@@ -43,9 +47,8 @@ export const omit = <
|
|
|
43
47
|
|
|
44
48
|
const baseValidationResult = recordType.validate(objectFilled);
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
>;
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
51
|
+
return Result.map(baseValidationResult, () => a as V);
|
|
49
52
|
};
|
|
50
53
|
|
|
51
54
|
const fill: Type<V>['fill'] = (a) => Obj.omit(recordType.fill(a), keysToOmit);
|
package/src/record/omit.test.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectType, Result } from 'ts-data-forge';
|
|
2
2
|
import { number } from '../primitives/index.mjs';
|
|
3
3
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
4
|
-
import { validationErrorsToMessages } from '../
|
|
4
|
+
import { validationErrorsToMessages } from '../utils/index.mjs';
|
|
5
5
|
import { omit } from './omit.mjs';
|
|
6
6
|
import { record } from './record.mjs';
|
|
7
7
|
|
|
@@ -73,6 +73,51 @@ describe('omit', () => {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test('validate returns input as-is for OK cases', () => {
|
|
77
|
+
const input: UnknownRecord = {
|
|
78
|
+
year: 2000,
|
|
79
|
+
month: 12,
|
|
80
|
+
};
|
|
81
|
+
const result = ym.validate(input);
|
|
82
|
+
expect(Result.isOk(result)).toBe(true);
|
|
83
|
+
if (Result.isOk(result)) {
|
|
84
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('truthy case with additional keys', () => {
|
|
89
|
+
const x: UnknownRecord = {
|
|
90
|
+
year: 2000,
|
|
91
|
+
month: 12,
|
|
92
|
+
aaa: 999,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = ym.validate(x);
|
|
96
|
+
expect(Result.isOk(result)).toBe(true);
|
|
97
|
+
|
|
98
|
+
if (Result.isOk(result)) {
|
|
99
|
+
expectType<typeof result.value, Ym>('=');
|
|
100
|
+
expect(result.value).toStrictEqual({
|
|
101
|
+
year: 2000,
|
|
102
|
+
month: 12,
|
|
103
|
+
aaa: 999,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('validate returns input as-is for OK cases with additional keys', () => {
|
|
109
|
+
const input: UnknownRecord = {
|
|
110
|
+
year: 2000,
|
|
111
|
+
month: 12,
|
|
112
|
+
aaa: 999,
|
|
113
|
+
};
|
|
114
|
+
const result = ym.validate(input);
|
|
115
|
+
expect(Result.isOk(result)).toBe(true);
|
|
116
|
+
if (Result.isOk(result)) {
|
|
117
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
76
121
|
test('falsy case', () => {
|
|
77
122
|
const x: UnknownRecord = {
|
|
78
123
|
year: 2000,
|
package/src/record/partial.mts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { expectType, ISet, isRecord, Obj, Result } from 'ts-data-forge';
|
|
2
2
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
createAssertFn,
|
|
5
|
+
createCastFn,
|
|
6
|
+
createIsFn,
|
|
7
|
+
createPrimitiveValidationError,
|
|
8
|
+
} from '../utils/index.mjs';
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Creates a Partial type. If keysToBeOptional is set, only those keys are
|
|
@@ -58,9 +62,7 @@ export const partial = <
|
|
|
58
62
|
const validationResult = recordType.validate(objectFilled);
|
|
59
63
|
|
|
60
64
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
61
|
-
return Result.map(validationResult,
|
|
62
|
-
Type<V>['validate']
|
|
63
|
-
>;
|
|
65
|
+
return Result.map(validationResult, () => a as V);
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
const fill: Type<V>['fill'] = (a) => {
|
|
@@ -4,7 +4,7 @@ import { type Type, type TypeOf } from '../type.mjs';
|
|
|
4
4
|
import {
|
|
5
5
|
type ValidationError,
|
|
6
6
|
validationErrorsToMessages,
|
|
7
|
-
} from '../
|
|
7
|
+
} from '../utils/index.mjs';
|
|
8
8
|
import { optional } from './optional.mjs';
|
|
9
9
|
import { partial } from './partial.mjs';
|
|
10
10
|
import { record } from './record.mjs';
|
|
@@ -88,6 +88,19 @@ describe('partial', () => {
|
|
|
88
88
|
}
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
test('validate returns input as-is for OK cases', () => {
|
|
92
|
+
const input: UnknownRecord = {
|
|
93
|
+
year: 2000,
|
|
94
|
+
month: 12,
|
|
95
|
+
date: 25,
|
|
96
|
+
};
|
|
97
|
+
const result = ymd.validate(input);
|
|
98
|
+
expect(Result.isOk(result)).toBe(true);
|
|
99
|
+
if (Result.isOk(result)) {
|
|
100
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
91
104
|
test('truthy case optional keys', () => {
|
|
92
105
|
const x: UnknownRecord = {};
|
|
93
106
|
|
|
@@ -100,6 +113,51 @@ describe('partial', () => {
|
|
|
100
113
|
}
|
|
101
114
|
});
|
|
102
115
|
|
|
116
|
+
test('validate returns input as-is for empty object', () => {
|
|
117
|
+
const input: UnknownRecord = {};
|
|
118
|
+
const result = ymd.validate(input);
|
|
119
|
+
expect(Result.isOk(result)).toBe(true);
|
|
120
|
+
if (Result.isOk(result)) {
|
|
121
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('truthy case with additional keys', () => {
|
|
126
|
+
const x: UnknownRecord = {
|
|
127
|
+
year: 2000,
|
|
128
|
+
month: 12,
|
|
129
|
+
date: 25,
|
|
130
|
+
aaa: 999,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const result = ymd.validate(x);
|
|
134
|
+
expectType<typeof result, Result<Ymd, readonly ValidationError[]>>('=');
|
|
135
|
+
expect(Result.isOk(result)).toBe(true);
|
|
136
|
+
|
|
137
|
+
if (Result.isOk(result)) {
|
|
138
|
+
expect(result.value).toStrictEqual({
|
|
139
|
+
year: 2000,
|
|
140
|
+
month: 12,
|
|
141
|
+
date: 25,
|
|
142
|
+
aaa: 999,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('validate returns input as-is for OK cases with additional keys', () => {
|
|
148
|
+
const input: UnknownRecord = {
|
|
149
|
+
year: 2000,
|
|
150
|
+
month: 12,
|
|
151
|
+
date: 25,
|
|
152
|
+
aaa: 999,
|
|
153
|
+
};
|
|
154
|
+
const result = ymd.validate(input);
|
|
155
|
+
expect(Result.isOk(result)).toBe(true);
|
|
156
|
+
if (Result.isOk(result)) {
|
|
157
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
103
161
|
test('falsy case 1', () => {
|
|
104
162
|
const x: UnknownRecord = {
|
|
105
163
|
year: 2000,
|
|
@@ -287,6 +345,18 @@ describe('partial', () => {
|
|
|
287
345
|
}
|
|
288
346
|
});
|
|
289
347
|
|
|
348
|
+
test('partiallyPartialType validate returns input as-is for OK cases', () => {
|
|
349
|
+
const input: UnknownRecord = {
|
|
350
|
+
year: 2000,
|
|
351
|
+
month: 12,
|
|
352
|
+
};
|
|
353
|
+
const result = ymd.validate(input);
|
|
354
|
+
expect(Result.isOk(result)).toBe(true);
|
|
355
|
+
if (Result.isOk(result)) {
|
|
356
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
290
360
|
test('falsy case', () => {
|
|
291
361
|
const x: UnknownRecord = {
|
|
292
362
|
year: 2000,
|
package/src/record/pick.mts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { expectType, isRecord, Obj, Result } from 'ts-data-forge';
|
|
2
2
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
createAssertFn,
|
|
5
|
+
createCastFn,
|
|
6
|
+
createIsFn,
|
|
7
|
+
createPrimitiveValidationError,
|
|
8
|
+
} from '../utils/index.mjs';
|
|
5
9
|
|
|
6
10
|
/** Creates a record type with keys picked. */
|
|
7
11
|
export const pick = <
|
|
@@ -44,9 +48,7 @@ export const pick = <
|
|
|
44
48
|
const baseValidationResult = recordType.validate(objectFilled);
|
|
45
49
|
|
|
46
50
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
47
|
-
return Result.map(baseValidationResult,
|
|
48
|
-
Type<V>['validate']
|
|
49
|
-
>;
|
|
51
|
+
return Result.map(baseValidationResult, () => a as V);
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
const fill: Type<V>['fill'] = (a) =>
|
package/src/record/pick.test.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectType, Result } from 'ts-data-forge';
|
|
2
2
|
import { number } from '../primitives/index.mjs';
|
|
3
3
|
import { type Type, type TypeOf } from '../type.mjs';
|
|
4
|
-
import { validationErrorsToMessages } from '../
|
|
4
|
+
import { validationErrorsToMessages } from '../utils/index.mjs';
|
|
5
5
|
import { pick } from './pick.mjs';
|
|
6
6
|
import { record } from './record.mjs';
|
|
7
7
|
|
|
@@ -73,6 +73,51 @@ describe('pick', () => {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test('validate returns input as-is for OK cases', () => {
|
|
77
|
+
const input: UnknownRecord = {
|
|
78
|
+
year: 2000,
|
|
79
|
+
month: 12,
|
|
80
|
+
};
|
|
81
|
+
const result = ym.validate(input);
|
|
82
|
+
expect(Result.isOk(result)).toBe(true);
|
|
83
|
+
if (Result.isOk(result)) {
|
|
84
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('truthy case with additional keys', () => {
|
|
89
|
+
const x: UnknownRecord = {
|
|
90
|
+
year: 2000,
|
|
91
|
+
month: 12,
|
|
92
|
+
aaa: 999,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = ym.validate(x);
|
|
96
|
+
expect(Result.isOk(result)).toBe(true);
|
|
97
|
+
|
|
98
|
+
if (Result.isOk(result)) {
|
|
99
|
+
expectType<typeof result.value, Ym>('=');
|
|
100
|
+
expect(result.value).toStrictEqual({
|
|
101
|
+
year: 2000,
|
|
102
|
+
month: 12,
|
|
103
|
+
aaa: 999,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('validate returns input as-is for OK cases with additional keys', () => {
|
|
109
|
+
const input: UnknownRecord = {
|
|
110
|
+
year: 2000,
|
|
111
|
+
month: 12,
|
|
112
|
+
aaa: 999,
|
|
113
|
+
};
|
|
114
|
+
const result = ym.validate(input);
|
|
115
|
+
expect(Result.isOk(result)).toBe(true);
|
|
116
|
+
if (Result.isOk(result)) {
|
|
117
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
76
121
|
test('falsy case', () => {
|
|
77
122
|
const x: UnknownRecord = {
|
|
78
123
|
year: 2000,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Result } from 'ts-data-forge';
|
|
2
2
|
import { number } from '../primitives/index.mjs';
|
|
3
|
-
import { validationErrorsToMessages } from '../
|
|
3
|
+
import { validationErrorsToMessages } from '../utils/index.mjs';
|
|
4
4
|
import { record } from './record.mjs';
|
|
5
5
|
|
|
6
6
|
describe('record allowExcessProperties option', () => {
|
|
@@ -73,6 +73,15 @@ describe('record allowExcessProperties option', () => {
|
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test('strictRecord validate returns input as-is for OK cases', () => {
|
|
77
|
+
const input = { name: 42, age: 25 };
|
|
78
|
+
const result = strictRecord.validate(input);
|
|
79
|
+
expect(Result.isOk(result)).toBe(true);
|
|
80
|
+
if (Result.isOk(result)) {
|
|
81
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
76
85
|
test('allowExcessProperties: true - accepts excess properties', () => {
|
|
77
86
|
const dataWithExcess = {
|
|
78
87
|
name: 42,
|
|
@@ -94,6 +103,15 @@ describe('record allowExcessProperties option', () => {
|
|
|
94
103
|
}
|
|
95
104
|
});
|
|
96
105
|
|
|
106
|
+
test('permissiveRecord validate returns input as-is for OK cases', () => {
|
|
107
|
+
const input = { name: 42, age: 25, extra: 'allowed' };
|
|
108
|
+
const result = permissiveRecord.validate(input);
|
|
109
|
+
expect(Result.isOk(result)).toBe(true);
|
|
110
|
+
if (Result.isOk(result)) {
|
|
111
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
97
115
|
test('default behavior - allows excess properties (allowExcessProperties defaults to true)', () => {
|
|
98
116
|
const dataWithExcess = {
|
|
99
117
|
name: 42,
|
|
@@ -115,6 +133,15 @@ describe('record allowExcessProperties option', () => {
|
|
|
115
133
|
}
|
|
116
134
|
});
|
|
117
135
|
|
|
136
|
+
test('defaultRecord validate returns input as-is for OK cases', () => {
|
|
137
|
+
const input = { name: 42, age: 25, extra: 'allowed by default' };
|
|
138
|
+
const result = defaultRecord.validate(input);
|
|
139
|
+
expect(Result.isOk(result)).toBe(true);
|
|
140
|
+
if (Result.isOk(result)) {
|
|
141
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
118
145
|
test('allowExcessProperties: false - multiple excess properties', () => {
|
|
119
146
|
const dataWithMultipleExcess = {
|
|
120
147
|
name: 42,
|
|
@@ -48,6 +48,16 @@ describe('record strict composition - simple tests', () => {
|
|
|
48
48
|
expect(result.value).toStrictEqual({ id: '123', name: 'John' });
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
test('pickedType validate returns input as-is for OK cases', () => {
|
|
53
|
+
const pickedType = pick(strictRecord, ['id', 'name']);
|
|
54
|
+
const input = { id: '123', name: 'John' };
|
|
55
|
+
const result = pickedType.validate(input);
|
|
56
|
+
expect(Result.isOk(result)).toBe(true);
|
|
57
|
+
if (Result.isOk(result)) {
|
|
58
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
59
|
+
}
|
|
60
|
+
});
|
|
51
61
|
});
|
|
52
62
|
|
|
53
63
|
describe('omit behavior with strict record', () => {
|
|
@@ -108,6 +118,15 @@ describe('record strict composition - simple tests', () => {
|
|
|
108
118
|
expect(Result.isErr(result)).toBe(true);
|
|
109
119
|
});
|
|
110
120
|
|
|
121
|
+
test('strictRecord validate returns input as-is for OK cases', () => {
|
|
122
|
+
const input = { id: '123', name: 'John', age: 25 };
|
|
123
|
+
const result = strictRecord.validate(input);
|
|
124
|
+
expect(Result.isOk(result)).toBe(true);
|
|
125
|
+
if (Result.isOk(result)) {
|
|
126
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
111
130
|
test('permissive record accepts excess properties', () => {
|
|
112
131
|
const data = { id: '123', name: 'John', age: 25, extra: 'allowed' };
|
|
113
132
|
|
|
@@ -115,6 +134,15 @@ describe('record strict composition - simple tests', () => {
|
|
|
115
134
|
expect(Result.isOk(result)).toBe(true);
|
|
116
135
|
});
|
|
117
136
|
|
|
137
|
+
test('permissiveRecord validate returns input as-is for OK cases', () => {
|
|
138
|
+
const input = { id: '123', name: 'John', age: 25, extra: 'allowed' };
|
|
139
|
+
const result = permissiveRecord.validate(input);
|
|
140
|
+
expect(Result.isOk(result)).toBe(true);
|
|
141
|
+
if (Result.isOk(result)) {
|
|
142
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
118
146
|
test('pick from strict record rejects excess properties', () => {
|
|
119
147
|
const strictPicked = pick(strictRecord, ['id', 'name']);
|
|
120
148
|
const data = { id: '123', name: 'John', extra: 'not allowed' };
|
|
@@ -130,5 +158,15 @@ describe('record strict composition - simple tests', () => {
|
|
|
130
158
|
const result = permissivePicked.validate(data);
|
|
131
159
|
expect(Result.isOk(result)).toBe(true);
|
|
132
160
|
});
|
|
161
|
+
|
|
162
|
+
test('permissivePicked validate returns input as-is for OK cases', () => {
|
|
163
|
+
const permissivePicked = pick(permissiveRecord, ['id', 'name']);
|
|
164
|
+
const input = { id: '123', name: 'John', extra: 'allowed' };
|
|
165
|
+
const result = permissivePicked.validate(input);
|
|
166
|
+
expect(Result.isOk(result)).toBe(true);
|
|
167
|
+
if (Result.isOk(result)) {
|
|
168
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
169
|
+
}
|
|
170
|
+
});
|
|
133
171
|
});
|
|
134
172
|
});
|