ts-fortress 2.2.1 → 2.2.2
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/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/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 +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/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/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
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
|
});
|
|
@@ -39,6 +39,15 @@ describe('record strict composition tests', () => {
|
|
|
39
39
|
}
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
test('pickedType validate returns input as-is for OK cases', () => {
|
|
43
|
+
const input = { id: '123', name: 'John' };
|
|
44
|
+
const result = pickedType.validate(input);
|
|
45
|
+
expect(Result.isOk(result)).toBe(true);
|
|
46
|
+
if (Result.isOk(result)) {
|
|
47
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
42
51
|
test('rejects data with excess properties (inherits strict behavior)', () => {
|
|
43
52
|
const dataWithExcess = { id: '123', name: 'John', extra: 'not allowed' };
|
|
44
53
|
|
|
@@ -94,6 +103,15 @@ describe('record strict composition tests', () => {
|
|
|
94
103
|
}
|
|
95
104
|
});
|
|
96
105
|
|
|
106
|
+
test('omittedType validate returns input as-is for OK cases', () => {
|
|
107
|
+
const input = { id: '123', name: 'John' };
|
|
108
|
+
const result = omittedType.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('rejects data with excess properties (inherits strict behavior)', () => {
|
|
98
116
|
const dataWithExcess = { id: '123', name: 'John', extra: 'not allowed' };
|
|
99
117
|
|
|
@@ -123,6 +141,7 @@ describe('record strict composition tests', () => {
|
|
|
123
141
|
|
|
124
142
|
if (Result.isOk(result)) {
|
|
125
143
|
expect(result.value).toStrictEqual({
|
|
144
|
+
age: 25,
|
|
126
145
|
id: '123',
|
|
127
146
|
name: 'John',
|
|
128
147
|
});
|
|
@@ -150,6 +169,15 @@ describe('record strict composition tests', () => {
|
|
|
150
169
|
}
|
|
151
170
|
});
|
|
152
171
|
|
|
172
|
+
test('partialType validate returns input as-is for OK cases', () => {
|
|
173
|
+
const input = { id: '123', name: 'John' };
|
|
174
|
+
const result = partialType.validate(input);
|
|
175
|
+
expect(Result.isOk(result)).toBe(true);
|
|
176
|
+
if (Result.isOk(result)) {
|
|
177
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
153
181
|
test('accepts empty object (all fields optional)', () => {
|
|
154
182
|
const emptyData = {};
|
|
155
183
|
|
|
@@ -164,6 +192,15 @@ describe('record strict composition tests', () => {
|
|
|
164
192
|
}
|
|
165
193
|
});
|
|
166
194
|
|
|
195
|
+
test('partialType validate returns input as-is for empty object', () => {
|
|
196
|
+
const input = {};
|
|
197
|
+
const result = partialType.validate(input);
|
|
198
|
+
expect(Result.isOk(result)).toBe(true);
|
|
199
|
+
if (Result.isOk(result)) {
|
|
200
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
167
204
|
test('rejects data with excess properties (inherits strict behavior)', () => {
|
|
168
205
|
const dataWithExcess = { id: '123', name: 'John', extra: 'not allowed' };
|
|
169
206
|
|
|
@@ -206,6 +243,18 @@ describe('record strict composition tests', () => {
|
|
|
206
243
|
}
|
|
207
244
|
});
|
|
208
245
|
|
|
246
|
+
test('partiallyPartialType validate returns input as-is for OK cases', () => {
|
|
247
|
+
const partiallyPartialType = partial(strictBaseRecord, {
|
|
248
|
+
keysToBeOptional: ['age', 'email'],
|
|
249
|
+
});
|
|
250
|
+
const input = { id: '123', name: 'John' };
|
|
251
|
+
const result = partiallyPartialType.validate(input);
|
|
252
|
+
expect(Result.isOk(result)).toBe(true);
|
|
253
|
+
if (Result.isOk(result)) {
|
|
254
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
209
258
|
test('partially partial rejects missing required fields', () => {
|
|
210
259
|
const partiallyPartialType = partial(strictBaseRecord, {
|
|
211
260
|
keysToBeOptional: ['age', 'email'],
|
|
@@ -362,6 +411,17 @@ describe('record strict composition tests', () => {
|
|
|
362
411
|
}
|
|
363
412
|
});
|
|
364
413
|
|
|
414
|
+
test('pickedPartialType validate returns input as-is for OK cases', () => {
|
|
415
|
+
const partialType = partial(strictBaseRecord);
|
|
416
|
+
const pickedPartialType = pick(partialType, ['id', 'name']);
|
|
417
|
+
const input = { id: '123', name: 'John' };
|
|
418
|
+
const result = pickedPartialType.validate(input);
|
|
419
|
+
expect(Result.isOk(result)).toBe(true);
|
|
420
|
+
if (Result.isOk(result)) {
|
|
421
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
365
425
|
test('partial of pick of strict record', () => {
|
|
366
426
|
const pickedType = pick(strictBaseRecord, ['id', 'name']);
|
|
367
427
|
const partialPickedType = partial(pickedType);
|
|
@@ -381,6 +441,17 @@ describe('record strict composition tests', () => {
|
|
|
381
441
|
}
|
|
382
442
|
});
|
|
383
443
|
|
|
444
|
+
test('partialPickedType validate returns input as-is for OK cases', () => {
|
|
445
|
+
const pickedType = pick(strictBaseRecord, ['id', 'name']);
|
|
446
|
+
const partialPickedType = partial(pickedType);
|
|
447
|
+
const input = { id: '123' };
|
|
448
|
+
const result = partialPickedType.validate(input);
|
|
449
|
+
expect(Result.isOk(result)).toBe(true);
|
|
450
|
+
if (Result.isOk(result)) {
|
|
451
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
384
455
|
test('nested compositions reject excess properties', () => {
|
|
385
456
|
const partialType = partial(strictBaseRecord);
|
|
386
457
|
const pickedPartialType = pick(partialType, ['id', 'name']);
|
package/src/record/record.mts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { isRecord, Result, tp } from 'ts-data-forge';
|
|
1
|
+
import { Arr, isRecord, Result, tp } 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
|
export const record = <const R extends ReadonlyRecord<string, Type<unknown>>>(
|
|
12
14
|
source: R,
|
|
@@ -48,32 +50,31 @@ export const record = <const R extends ReadonlyRecord<string, Type<unknown>>>(
|
|
|
48
50
|
]);
|
|
49
51
|
}
|
|
50
52
|
|
|
51
|
-
const defaultErrors: readonly ValidationError[] =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
53
|
+
const defaultErrors: readonly ValidationError[] = Arr.generate(
|
|
54
|
+
function* () {
|
|
55
|
+
for (const [k, valueType] of Object.entries(source)) {
|
|
56
|
+
if (!Object.hasOwn(a, k)) {
|
|
57
|
+
if (source[k]?.optional !== true) {
|
|
58
|
+
yield {
|
|
59
|
+
path: [k],
|
|
60
|
+
actualValue: a,
|
|
61
|
+
typeName: typeNameFilled,
|
|
62
|
+
expectedType: typeNameFilled,
|
|
63
|
+
message: `Missing required key "${k}"`,
|
|
64
|
+
} satisfies ValidationErrorWithMessage;
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
// The case where the key exists in the object
|
|
68
|
+
const v = a[k];
|
|
69
|
+
const res = valueType.validate(v);
|
|
70
|
+
|
|
71
|
+
if (Result.isErr(res)) {
|
|
72
|
+
yield* prependPathToValidationErrors(res.value, k);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
);
|
|
77
78
|
|
|
78
79
|
// Check for excess properties if allowExcessProperties is false
|
|
79
80
|
if (!allowExcessProperties) {
|
|
@@ -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 { optional } from './optional.mjs';
|
|
6
6
|
import { record } from './record.mjs';
|
|
7
7
|
|
|
@@ -143,6 +143,19 @@ describe('record', () => {
|
|
|
143
143
|
]);
|
|
144
144
|
}
|
|
145
145
|
});
|
|
146
|
+
|
|
147
|
+
test('validate returns input as-is for OK cases', () => {
|
|
148
|
+
const input = {
|
|
149
|
+
year: 2023,
|
|
150
|
+
month: 6,
|
|
151
|
+
date: 15,
|
|
152
|
+
};
|
|
153
|
+
const result = ymd.validate(input);
|
|
154
|
+
expect(Result.isOk(result)).toBe(true);
|
|
155
|
+
if (Result.isOk(result)) {
|
|
156
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
157
|
+
}
|
|
158
|
+
});
|
|
146
159
|
});
|
|
147
160
|
|
|
148
161
|
describe('fill', () => {
|
|
@@ -311,6 +324,18 @@ describe('partial record', () => {
|
|
|
311
324
|
]);
|
|
312
325
|
}
|
|
313
326
|
});
|
|
327
|
+
|
|
328
|
+
test('validate returns input as-is for OK cases', () => {
|
|
329
|
+
const input = {
|
|
330
|
+
year: 2024,
|
|
331
|
+
month: 8,
|
|
332
|
+
};
|
|
333
|
+
const result = ymd.validate(input);
|
|
334
|
+
expect(Result.isOk(result)).toBe(true);
|
|
335
|
+
if (Result.isOk(result)) {
|
|
336
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
337
|
+
}
|
|
338
|
+
});
|
|
314
339
|
});
|
|
315
340
|
|
|
316
341
|
describe('fill', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectType, Result } from 'ts-data-forge';
|
|
2
2
|
import { number, string } from '../primitives/index.mjs';
|
|
3
3
|
import { type TypeOf } from '../type.mjs';
|
|
4
|
-
import { validationErrorsToMessages } from '../
|
|
4
|
+
import { validationErrorsToMessages } from '../utils/index.mjs';
|
|
5
5
|
import { record, strictRecord } from './record.mjs';
|
|
6
6
|
|
|
7
7
|
describe('strictRecord', () => {
|
|
@@ -49,6 +49,15 @@ describe('strictRecord', () => {
|
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
test('validate returns input as-is for OK cases', () => {
|
|
53
|
+
const input = { name: 'John', age: 30 };
|
|
54
|
+
const result = userType.validate(input);
|
|
55
|
+
expect(Result.isOk(result)).toBe(true);
|
|
56
|
+
if (Result.isOk(result)) {
|
|
57
|
+
expect(result.value).toBe(input); // ✅ same reference
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
52
61
|
test('falsy case - excess properties', () => {
|
|
53
62
|
const userWithExtra = { name: 'John', age: 30, extra: 'not allowed' };
|
|
54
63
|
|
package/src/type.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { type Type } from '../type.mjs';
|
|
|
3
3
|
import {
|
|
4
4
|
validationErrorsToMessages,
|
|
5
5
|
type ValidationError,
|
|
6
|
-
} from '
|
|
6
|
+
} from './validation-error.mjs';
|
|
7
7
|
|
|
8
8
|
const validationResultToString = (result: readonly ValidationError[]): string =>
|
|
9
9
|
`\n${validationErrorsToMessages(result).join(',\n')}`;
|
|
@@ -3,7 +3,7 @@ import { type Type } from '../type.mjs';
|
|
|
3
3
|
import {
|
|
4
4
|
validationErrorsToMessages,
|
|
5
5
|
type ValidationError,
|
|
6
|
-
} from '
|
|
6
|
+
} from './validation-error.mjs';
|
|
7
7
|
|
|
8
8
|
const validationResultToString = (result: readonly ValidationError[]): string =>
|
|
9
9
|
`\n${validationErrorsToMessages(result).join(',\n')}`;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Result } from 'ts-data-forge';
|
|
2
2
|
import { type Type } from '../type.mjs';
|
|
3
|
-
import { createPrimitiveValidationError } from '../validation-error.mjs';
|
|
4
3
|
import { createAssertFn } from './create-assert-fn.mjs';
|
|
5
4
|
import { createCastFn } from './create-cast-fn.mjs';
|
|
5
|
+
import { createPrimitiveValidationError } from './validation-error.mjs';
|
|
6
6
|
|
|
7
7
|
export const createPrimitiveType = <A extends Primitive>({
|
|
8
8
|
typeName,
|
package/src/utils/index.mts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation-error.d.mts","sourceRoot":"","sources":["../src/validation-error.mts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,iFAAiF;IACjF,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,8CAA8C;IAC9C,WAAW,EAAE,OAAO,CAAC;IACrB,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,iBAAiB,CACxD,UAAU,CAAC,eAAe,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CACvE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,GAAI,OAAO,eAAe,KAAG,MASjE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GACrC,QAAQ,SAAS,eAAe,EAAE,KACjC,SAAS,MAAM,EAA0C,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,6BAA6B,GACxC,QAAQ,SAAS,eAAe,EAAE,EAClC,aAAa,MAAM,KAClB,SAAS,eAAe,EAItB,CAAC;AAEN;;GAEG;AACH,eAAO,MAAM,8BAA8B,GACzC,QAAQ,SAAS,eAAe,EAAE,EAClC,OAAO,MAAM,KACZ,SAAS,eAAe,EAC8B,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,8BAA8B,GAAI,0CAI5C,QAAQ,CAAC;IACV,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,KAAG,eAMH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation-error.mjs","sources":["../src/validation-error.mts"],"sourcesContent":[null],"names":[],"mappings":"AAoBA;;AAEG;AACI,MAAM,wBAAwB,GAAG,CAAC,KAAsB,KAAY;IACzE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,CAAA,IAAA,EAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA,CAAE,GAAG,EAAE;AAC1E,IAAA,MAAM,aAAa,GAAG,OAAO,KAAK,CAAC,WAAW;AAE9C,IAAA,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE;AAC/B,QAAA,OAAO,GAAG,KAAK,CAAC,OAAO,CAAA,EAAG,OAAO,EAAE;IACrC;IAEA,OAAO,CAAA,SAAA,EAAY,KAAK,CAAC,YAAY,GAAG,OAAO,CAAA,MAAA,EAAS,aAAa,CAAA,CAAE;AACzE;AAEA;;;AAGG;AACI,MAAM,0BAA0B,GAAG,CACxC,MAAkC,KACZ,MAAM,CAAC,GAAG,CAAC,wBAAwB;AAE3D;;AAEG;MACU,6BAA6B,GAAG,CAC3C,MAAkC,EAClC,WAAmB,KAEnB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM;AACrB,IAAA,GAAG,KAAK;IACR,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;AACnC,CAAA,CAAC;AAEJ;;AAEG;MACU,8BAA8B,GAAG,CAC5C,MAAkC,EAClC,KAAa,KAEb,6BAA6B,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE;AAExD;;AAEG;AACI,MAAM,8BAA8B,GAAG,CAAC,EAC7C,WAAW,EACX,YAAY,EACZ,QAAQ,GAKR,MAAuB;AACvB,IAAA,IAAI,EAAE,EAAE;IACR,WAAW;IACX,YAAY;IACZ,QAAQ;AACR,IAAA,OAAO,EAAE,SAAS;AACnB,CAAA;;;;"}
|