ts-fortress 7.0.6 → 7.1.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 +2 -0
- package/dist/array/array-at-most-length.d.mts +8 -0
- package/dist/array/array-at-most-length.d.mts.map +1 -0
- package/dist/array/array-at-most-length.mjs +73 -0
- package/dist/array/array-at-most-length.mjs.map +1 -0
- package/dist/array/array-bounded-length.d.mts +8 -0
- package/dist/array/array-bounded-length.d.mts.map +1 -0
- package/dist/array/array-bounded-length.mjs +80 -0
- package/dist/array/array-bounded-length.mjs.map +1 -0
- package/dist/array/index.d.mts +2 -0
- package/dist/array/index.d.mts.map +1 -1
- package/dist/array/index.mjs +2 -0
- package/dist/array/index.mjs.map +1 -1
- package/dist/entry-point.mjs +2 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/dist/utils/validation-error.d.mts +9 -0
- package/dist/utils/validation-error.d.mts.map +1 -1
- package/dist/utils/validation-error.mjs +4 -0
- package/dist/utils/validation-error.mjs.map +1 -1
- package/package.json +10 -10
- package/src/array/array-at-most-length.mts +106 -0
- package/src/array/array-at-most-length.test.mts +206 -0
- package/src/array/array-bounded-length.mts +118 -0
- package/src/array/array-bounded-length.test.mts +252 -0
- package/src/array/index.mts +2 -0
- package/src/utils/validation-error.mts +17 -0
package/README.md
CHANGED
|
@@ -1040,6 +1040,8 @@ type ValidationError = Readonly<{
|
|
|
1040
1040
|
- `t.tuple([t1, t2, ..., tN])` - Fixed-length tuple validation
|
|
1041
1041
|
- `t.arrayOfLength(size, elementType)` - Fixed-length array validation
|
|
1042
1042
|
- `t.arrayAtLeastLength(size, elementType)` - Array validation with a minimum length
|
|
1043
|
+
- `t.arrayAtMostLength(size, elementType)` - Array validation with a maximum length
|
|
1044
|
+
- `t.arrayBoundedLength(min, max, elementType)` - Array validation with a length between `min` and `max` (inclusive)
|
|
1043
1045
|
|
|
1044
1046
|
### Objects
|
|
1045
1047
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ArrayAtMostLen, type SmallUint } from 'ts-type-forge';
|
|
2
|
+
import { type Type } from '../type.mjs';
|
|
3
|
+
export type { ArrayAtMostLen } from 'ts-type-forge';
|
|
4
|
+
export declare const arrayAtMostLength: <A, N extends SmallUint>(size: N, elementType: Type<A>, options?: Partial<Readonly<{
|
|
5
|
+
typeName: string;
|
|
6
|
+
defaultValue: ArrayAtMostLen<N, A>;
|
|
7
|
+
}>>) => Type<ArrayAtMostLen<N, A>>;
|
|
8
|
+
//# sourceMappingURL=array-at-most-length.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array-at-most-length.d.mts","sourceRoot":"","sources":["../../src/array/array-at-most-length.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAUxC,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,eAAO,MAAM,iBAAiB,GAAI,CAAC,EAAE,CAAC,SAAS,SAAS,EACtD,MAAM,CAAC,EACP,aAAa,IAAI,CAAC,CAAC,CAAC,EACpB,UAAU,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACpC,CAAC,CACH,KACA,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAkF3B,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { memoizeFunction, Arr, Result } from 'ts-data-forge';
|
|
2
|
+
import { createAssertFn } from '../utils/create-assert-fn.mjs';
|
|
3
|
+
import { createCastFn } from '../utils/create-cast-fn.mjs';
|
|
4
|
+
import { createIsFn } from '../utils/create-is-fn.mjs';
|
|
5
|
+
import { createPrimitiveValidationError, prependIndexToValidationErrors } from '../utils/validation-error.mjs';
|
|
6
|
+
|
|
7
|
+
const arrayAtMostLength = (size, elementType, options) => {
|
|
8
|
+
const typeName = options?.typeName ?? `ArrayAtMostLen<${size}, ${elementType.typeName}>`;
|
|
9
|
+
const getDefaultValue = memoizeFunction(() => options?.defaultValue ??
|
|
10
|
+
// The empty array is the shortest value satisfying `length <= size`.
|
|
11
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
12
|
+
Arr.create(0, elementType.defaultValue));
|
|
13
|
+
const validate = (a) => {
|
|
14
|
+
if (!Arr.isArray(a)) {
|
|
15
|
+
return Result.err([
|
|
16
|
+
createPrimitiveValidationError({
|
|
17
|
+
actualValue: a,
|
|
18
|
+
expectedType: 'array',
|
|
19
|
+
typeName,
|
|
20
|
+
details: undefined,
|
|
21
|
+
}),
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
24
|
+
if (a.length > size) {
|
|
25
|
+
return Result.err([
|
|
26
|
+
{
|
|
27
|
+
path: [],
|
|
28
|
+
actualValue: a,
|
|
29
|
+
expectedType: typeName,
|
|
30
|
+
typeName,
|
|
31
|
+
details: {
|
|
32
|
+
kind: 'array-max-length',
|
|
33
|
+
maxLength: size,
|
|
34
|
+
actualLength: a.length,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
const errors = Arr.generate(function* () {
|
|
40
|
+
for (const [index, el] of a.entries()) {
|
|
41
|
+
const res = elementType.validate(el);
|
|
42
|
+
if (Result.isErr(res)) {
|
|
43
|
+
yield* prependIndexToValidationErrors(res.value, index);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
if (Arr.isNonEmpty(errors)) {
|
|
48
|
+
return Result.err(errors);
|
|
49
|
+
}
|
|
50
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
51
|
+
return Result.ok(a);
|
|
52
|
+
};
|
|
53
|
+
const fill = (a) => Arr.isArray(a)
|
|
54
|
+
? // Keep the input but trim down to at most `size` elements.
|
|
55
|
+
// TODO: remove as
|
|
56
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
57
|
+
Arr.map(Arr.take(a, size), (el) => elementType.fill(el))
|
|
58
|
+
: getDefaultValue();
|
|
59
|
+
return {
|
|
60
|
+
typeName,
|
|
61
|
+
get defaultValue() {
|
|
62
|
+
return getDefaultValue();
|
|
63
|
+
},
|
|
64
|
+
fill,
|
|
65
|
+
validate,
|
|
66
|
+
is: createIsFn(validate),
|
|
67
|
+
cast: createCastFn(validate),
|
|
68
|
+
assertIs: createAssertFn(validate),
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export { arrayAtMostLength };
|
|
73
|
+
//# sourceMappingURL=array-at-most-length.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array-at-most-length.mjs","sources":["../../src/array/array-at-most-length.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAcO,MAAM,iBAAiB,GAAG,CAC/B,IAAO,EACP,WAAoB,EACpB,OAKC,KAC6B;AAG9B,IAAA,MAAM,QAAQ,GACZ,OAAO,EAAE,QAAQ,IAAI,CAAA,eAAA,EAAkB,IAAI,CAAA,EAAA,EAAK,WAAW,CAAC,QAAQ,GAAG;IAEzE,MAAM,eAAe,GAAG,eAAe,CACrC,MACE,OAAO,EAAE,YAAY;;;QAGpB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,YAAY,CAAO,CACjD;AAED,IAAA,MAAM,QAAQ,GAAwB,CAAC,CAAC,KAAI;QAC1C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACnB,OAAO,MAAM,CAAC,GAAG,CAAC;AAChB,gBAAA,8BAA8B,CAAC;AAC7B,oBAAA,WAAW,EAAE,CAAC;AACd,oBAAA,YAAY,EAAE,OAAO;oBACrB,QAAQ;AACR,oBAAA,OAAO,EAAE,SAAS;iBACnB,CAAC;AACH,aAAA,CAAC;QACJ;AAEA,QAAA,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE;YACnB,OAAO,MAAM,CAAC,GAAG,CAAC;AAChB,gBAAA;AACE,oBAAA,IAAI,EAAE,EAAE;AACR,oBAAA,WAAW,EAAE,CAAC;AACd,oBAAA,YAAY,EAAE,QAAQ;oBACtB,QAAQ;AACR,oBAAA,OAAO,EAAE;AACP,wBAAA,IAAI,EAAE,kBAAkB;AACxB,wBAAA,SAAS,EAAE,IAAI;wBACf,YAAY,EAAE,CAAC,CAAC,MAAM;AACvB,qBAAA;AACwB,iBAAA;AAC5B,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,MAAM,GAA+B,GAAG,CAAC,QAAQ,CAAC,aAAS;AAC/D,YAAA,KAAK,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBACrC,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;AAEpC,gBAAA,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;oBACrB,OAAO,8BAA8B,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;gBACzD;YACF;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC1B,YAAA,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QAC3B;;AAGA,QAAA,OAAO,MAAM,CAAC,EAAE,CAAC,CAAiB,CAAC;AACrC,IAAA,CAAC;AAED,IAAA,MAAM,IAAI,GAAoB,CAAC,CAAC,KAC9B,GAAG,CAAC,OAAO,CAAC,CAAC;AACX;;;YAGG,GAAG,CAAC,GAAG,CACN,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EACjB,CAAC,EAAE,KAAK,WAAW,CAAC,IAAI,CAAC,EAAE,CAAa;UAE1C,eAAe,EAAE;IAEvB,OAAO;QACL,QAAQ;AACR,QAAA,IAAI,YAAY,GAAA;YACd,OAAO,eAAe,EAAE;QAC1B,CAAC;QACD,IAAI;QACJ,QAAQ;AACR,QAAA,EAAE,EAAE,UAAU,CAAC,QAAQ,CAAC;AACxB,QAAA,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;AAC5B,QAAA,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC;KACnC;AACH;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ArrayBoundedLen, type SmallUint } from 'ts-type-forge';
|
|
2
|
+
import { type Type } from '../type.mjs';
|
|
3
|
+
export type { ArrayBoundedLen } from 'ts-type-forge';
|
|
4
|
+
export declare const arrayBoundedLength: <A, Min extends SmallUint, Max extends SmallUint>(min: Min, max: Max, elementType: Type<A>, options?: Partial<Readonly<{
|
|
5
|
+
typeName: string;
|
|
6
|
+
defaultValue: ArrayBoundedLen<Min, Max, A>;
|
|
7
|
+
}>>) => Type<ArrayBoundedLen<Min, Max, A>>;
|
|
8
|
+
//# sourceMappingURL=array-bounded-length.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array-bounded-length.d.mts","sourceRoot":"","sources":["../../src/array/array-bounded-length.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAUxC,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,eAAO,MAAM,kBAAkB,GAC7B,CAAC,EACD,GAAG,SAAS,SAAS,EACrB,GAAG,SAAS,SAAS,EAErB,KAAK,GAAG,EACR,KAAK,GAAG,EACR,aAAa,IAAI,CAAC,CAAC,CAAC,EACpB,UAAU,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;CAC5C,CAAC,CACH,KACA,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAyFnC,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { memoizeFunction, Arr, Result } from 'ts-data-forge';
|
|
2
|
+
import { createAssertFn } from '../utils/create-assert-fn.mjs';
|
|
3
|
+
import { createCastFn } from '../utils/create-cast-fn.mjs';
|
|
4
|
+
import { createIsFn } from '../utils/create-is-fn.mjs';
|
|
5
|
+
import { createPrimitiveValidationError, prependIndexToValidationErrors } from '../utils/validation-error.mjs';
|
|
6
|
+
|
|
7
|
+
const arrayBoundedLength = (min, max, elementType, options) => {
|
|
8
|
+
const typeName = options?.typeName ??
|
|
9
|
+
`ArrayBoundedLen<${min}, ${max}, ${elementType.typeName}>`;
|
|
10
|
+
const getDefaultValue = memoizeFunction(() => options?.defaultValue ??
|
|
11
|
+
// An array of the minimum length is the shortest value within the range.
|
|
12
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
13
|
+
Arr.create(min, elementType.defaultValue));
|
|
14
|
+
const validate = (a) => {
|
|
15
|
+
if (!Arr.isArray(a)) {
|
|
16
|
+
return Result.err([
|
|
17
|
+
createPrimitiveValidationError({
|
|
18
|
+
actualValue: a,
|
|
19
|
+
expectedType: 'array',
|
|
20
|
+
typeName,
|
|
21
|
+
details: undefined,
|
|
22
|
+
}),
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
if (a.length < min || max < a.length) {
|
|
26
|
+
return Result.err([
|
|
27
|
+
{
|
|
28
|
+
path: [],
|
|
29
|
+
actualValue: a,
|
|
30
|
+
expectedType: typeName,
|
|
31
|
+
typeName,
|
|
32
|
+
details: {
|
|
33
|
+
kind: 'array-range-length',
|
|
34
|
+
minLength: min,
|
|
35
|
+
maxLength: max,
|
|
36
|
+
actualLength: a.length,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
]);
|
|
40
|
+
}
|
|
41
|
+
const errors = Arr.generate(function* () {
|
|
42
|
+
for (const [index, el] of a.entries()) {
|
|
43
|
+
const res = elementType.validate(el);
|
|
44
|
+
if (Result.isErr(res)) {
|
|
45
|
+
yield* prependIndexToValidationErrors(res.value, index);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
if (Arr.isNonEmpty(errors)) {
|
|
50
|
+
return Result.err(errors);
|
|
51
|
+
}
|
|
52
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
53
|
+
return Result.ok(a);
|
|
54
|
+
};
|
|
55
|
+
const fill = (a) => {
|
|
56
|
+
if (!Arr.isArray(a)) {
|
|
57
|
+
return getDefaultValue();
|
|
58
|
+
}
|
|
59
|
+
// Trim down to at most `max`, then pad up to at least `min`.
|
|
60
|
+
const capped = Arr.take(a, max);
|
|
61
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
62
|
+
return (capped.length >= min
|
|
63
|
+
? Arr.map(capped, (el) => elementType.fill(el))
|
|
64
|
+
: Arr.map(Arr.seq(min), (i) => elementType.fill(capped[i])));
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
typeName,
|
|
68
|
+
get defaultValue() {
|
|
69
|
+
return getDefaultValue();
|
|
70
|
+
},
|
|
71
|
+
fill,
|
|
72
|
+
validate,
|
|
73
|
+
is: createIsFn(validate),
|
|
74
|
+
cast: createCastFn(validate),
|
|
75
|
+
assertIs: createAssertFn(validate),
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export { arrayBoundedLength };
|
|
80
|
+
//# sourceMappingURL=array-bounded-length.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array-bounded-length.mjs","sources":["../../src/array/array-bounded-length.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAcO,MAAM,kBAAkB,GAAG,CAKhC,GAAQ,EACR,GAAQ,EACR,WAAoB,EACpB,OAKC,KACqC;AAGtC,IAAA,MAAM,QAAQ,GACZ,OAAO,EAAE,QAAQ;QACjB,CAAA,gBAAA,EAAmB,GAAG,KAAK,GAAG,CAAA,EAAA,EAAK,WAAW,CAAC,QAAQ,GAAG;IAE5D,MAAM,eAAe,GAAG,eAAe,CACrC,MACE,OAAO,EAAE,YAAY;;;QAGpB,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,YAAY,CAAO,CACnD;AAED,IAAA,MAAM,QAAQ,GAAwB,CAAC,CAAC,KAAI;QAC1C,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACnB,OAAO,MAAM,CAAC,GAAG,CAAC;AAChB,gBAAA,8BAA8B,CAAC;AAC7B,oBAAA,WAAW,EAAE,CAAC;AACd,oBAAA,YAAY,EAAE,OAAO;oBACrB,QAAQ;AACR,oBAAA,OAAO,EAAE,SAAS;iBACnB,CAAC;AACH,aAAA,CAAC;QACJ;AAEA,QAAA,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE;YACpC,OAAO,MAAM,CAAC,GAAG,CAAC;AAChB,gBAAA;AACE,oBAAA,IAAI,EAAE,EAAE;AACR,oBAAA,WAAW,EAAE,CAAC;AACd,oBAAA,YAAY,EAAE,QAAQ;oBACtB,QAAQ;AACR,oBAAA,OAAO,EAAE;AACP,wBAAA,IAAI,EAAE,oBAAoB;AAC1B,wBAAA,SAAS,EAAE,GAAG;AACd,wBAAA,SAAS,EAAE,GAAG;wBACd,YAAY,EAAE,CAAC,CAAC,MAAM;AACvB,qBAAA;AACwB,iBAAA;AAC5B,aAAA,CAAC;QACJ;AAEA,QAAA,MAAM,MAAM,GAA+B,GAAG,CAAC,QAAQ,CAAC,aAAS;AAC/D,YAAA,KAAK,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBACrC,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;AAEpC,gBAAA,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;oBACrB,OAAO,8BAA8B,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;gBACzD;YACF;AACF,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;AAC1B,YAAA,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;QAC3B;;AAGA,QAAA,OAAO,MAAM,CAAC,EAAE,CAAC,CAAiB,CAAC;AACrC,IAAA,CAAC;AAED,IAAA,MAAM,IAAI,GAAoB,CAAC,CAAC,KAAI;QAClC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACnB,OAAO,eAAe,EAAE;QAC1B;;QAGA,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC;;AAG/B,QAAA,QACE,MAAM,CAAC,MAAM,IAAI;AACf,cAAE,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,WAAW,CAAC,IAAI,CAAC,EAAE,CAAa;AAC1D,cAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAa,CAAC;AAE7E,IAAA,CAAC;IAED,OAAO;QACL,QAAQ;AACR,QAAA,IAAI,YAAY,GAAA;YACd,OAAO,eAAe,EAAE;QAC1B,CAAC;QACD,IAAI;QACJ,QAAQ;AACR,QAAA,EAAE,EAAE,UAAU,CAAC,QAAQ,CAAC;AACxB,QAAA,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;AAC5B,QAAA,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAC;KACnC;AACH;;;;"}
|
package/dist/array/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/array/index.mts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/array/index.mts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
package/dist/array/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { arrayAtLeastLength } from './array-at-least-length.mjs';
|
|
2
|
+
export { arrayAtMostLength } from './array-at-most-length.mjs';
|
|
3
|
+
export { arrayBoundedLength } from './array-bounded-length.mjs';
|
|
2
4
|
export { arrayOfLength } from './array-of-length.mjs';
|
|
3
5
|
export { array } from './array.mjs';
|
|
4
6
|
export { nonEmptyArray } from './non-empty-array.mjs';
|
package/dist/array/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/dist/entry-point.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { FiniteNumber, Int, Int16, Int32, Int8, NonNegativeFiniteNumber, NonNegativeInt16, NonNegativeInt32, NonZeroFiniteNumber, NonZeroInt, NonZeroInt16, NonZeroInt32, NonZeroSafeInt, NonZeroUint16, NonZeroUint32, PositiveFiniteNumber, PositiveInt, PositiveInt16, PositiveInt32, PositiveSafeInt, PositiveUint16, PositiveUint32, Result, SafeInt, SafeUint, Uint, Uint16, Uint32, Uint8, asFiniteNumber, asInt, asInt16, asInt32, asInt8, asNonNegativeFiniteNumber, asNonNegativeInt16, asNonNegativeInt32, asNonZeroFiniteNumber, asNonZeroInt, asNonZeroInt16, asNonZeroInt32, asNonZeroSafeInt, asNonZeroUint16, asNonZeroUint32, asPositiveFiniteNumber, asPositiveInt, asPositiveInt16, asPositiveInt32, asPositiveSafeInt, asPositiveUint16, asPositiveUint32, asSafeInt, asSafeUint, asUint, asUint16, asUint32, asUint8, isBigint, isFiniteNumber, isInt, isInt16, isInt32, isInt8, isNonNegativeFiniteNumber, isNonNegativeInt16, isNonNegativeInt32, isNonZeroFiniteNumber, isNonZeroInt, isNonZeroInt16, isNonZeroInt32, isNonZeroSafeInt, isNonZeroUint16, isNonZeroUint32, isPositiveFiniteNumber, isPositiveInt, isPositiveInt16, isPositiveInt32, isPositiveSafeInt, isPositiveUint16, isPositiveUint32, isSafeInt, isSafeUint, isUint, isUint16, isUint32, isUint8 } from 'ts-data-forge';
|
|
2
2
|
export { arrayAtLeastLength } from './array/array-at-least-length.mjs';
|
|
3
|
+
export { arrayAtMostLength } from './array/array-at-most-length.mjs';
|
|
4
|
+
export { arrayBoundedLength } from './array/array-bounded-length.mjs';
|
|
3
5
|
export { arrayOfLength } from './array/array-of-length.mjs';
|
|
4
6
|
export { array } from './array/array.mjs';
|
|
5
7
|
export { nonEmptyArray } from './array/non-empty-array.mjs';
|
package/dist/entry-point.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-point.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry-point.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { arrayAtLeastLength } from './array/array-at-least-length.mjs';
|
|
2
|
+
export { arrayAtMostLength } from './array/array-at-most-length.mjs';
|
|
3
|
+
export { arrayBoundedLength } from './array/array-bounded-length.mjs';
|
|
2
4
|
export { arrayOfLength } from './array/array-of-length.mjs';
|
|
3
5
|
export { array } from './array/array.mjs';
|
|
4
6
|
export { nonEmptyArray } from './array/non-empty-array.mjs';
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -22,6 +22,15 @@ export type ValidationErrorDetails = Readonly<{
|
|
|
22
22
|
kind: 'array-min-length';
|
|
23
23
|
minLength: number;
|
|
24
24
|
actualLength: number;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'array-max-length';
|
|
27
|
+
maxLength: number;
|
|
28
|
+
actualLength: number;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'array-range-length';
|
|
31
|
+
minLength: number;
|
|
32
|
+
maxLength: number;
|
|
33
|
+
actualLength: number;
|
|
25
34
|
} | {
|
|
26
35
|
kind: 'non-empty-array';
|
|
27
36
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-error.d.mts","sourceRoot":"","sources":["../../src/utils/validation-error.mts"],"names":[],"mappings":"AAEA,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CACzC;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,IAAI,EAAE,kBAAkB,CAAC;CAC1B,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B,GACD;IACE,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,iBAAiB,CAAC;CACzB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb,GACD;IACE,IAAI,EAAE,YAAY,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB,CACJ,CAAC;AAEF;;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,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;CAC9C,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,wBAAwB,GACnC,OAAO,eAAe,EACtB,8BAA6B,MAAW,KACvC,MAyBF,CAAC;
|
|
1
|
+
{"version":3,"file":"validation-error.d.mts","sourceRoot":"","sources":["../../src/utils/validation-error.mts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,10 @@ const createDetailsMessage = (error, maxLengthToPrintActualValue) => {
|
|
|
41
41
|
return `expected array of length ${error.details.expectedLength} but length ${error.details.actualLength} was passed.`;
|
|
42
42
|
case 'array-min-length':
|
|
43
43
|
return `expected array of length ${error.details.minLength} or more but length ${error.details.actualLength} was passed.`;
|
|
44
|
+
case 'array-max-length':
|
|
45
|
+
return `expected array of length ${error.details.maxLength} or less but length ${error.details.actualLength} was passed.`;
|
|
46
|
+
case 'array-range-length':
|
|
47
|
+
return `expected array of length between ${error.details.minLength} and ${error.details.maxLength} but length ${error.details.actualLength} was passed.`;
|
|
44
48
|
case 'non-empty-array':
|
|
45
49
|
return 'expected non-empty array but empty array was passed.';
|
|
46
50
|
case 'missing-key':
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-error.mjs","sources":["../../src/utils/validation-error.mts"],"sourcesContent":[null],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"validation-error.mjs","sources":["../../src/utils/validation-error.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-fortress",
|
|
3
|
-
"version": "7.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript"
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
"z:vitest:node": "pnpm run z:vitest --project='Node.js'"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@sindresorhus/is": "8.0.0",
|
|
79
|
-
"ts-data-forge": "6.9.
|
|
80
|
-
"ts-type-forge": "3.
|
|
78
|
+
"@sindresorhus/is": "^8.0.0",
|
|
79
|
+
"ts-data-forge": "^6.9.6",
|
|
80
|
+
"ts-type-forge": "^3.1.0"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@rollup/plugin-replace": "6.0.3",
|
|
@@ -98,10 +98,10 @@
|
|
|
98
98
|
"cspell": "10.0.0",
|
|
99
99
|
"dedent": "1.7.2",
|
|
100
100
|
"eslint": "9.39.4",
|
|
101
|
-
"eslint-config-typed": "4.9.
|
|
101
|
+
"eslint-config-typed": "4.9.8",
|
|
102
102
|
"fast-glob": "3.3.3",
|
|
103
103
|
"fp-ts": "2.16.11",
|
|
104
|
-
"github-settings-as-code": "1.2.
|
|
104
|
+
"github-settings-as-code": "1.2.9",
|
|
105
105
|
"io-ts": "2.2.22",
|
|
106
106
|
"jiti": "2.6.1",
|
|
107
107
|
"markdownlint": "0.40.0",
|
|
@@ -113,8 +113,8 @@
|
|
|
113
113
|
"prettier-plugin-packagejson": "3.0.2",
|
|
114
114
|
"rollup": "4.60.2",
|
|
115
115
|
"semantic-release": "25.0.3",
|
|
116
|
-
"ts-codemod-lib": "2.1.
|
|
117
|
-
"ts-repo-utils": "10.0.
|
|
116
|
+
"ts-codemod-lib": "2.1.7",
|
|
117
|
+
"ts-repo-utils": "10.0.3",
|
|
118
118
|
"tslib": "2.8.1",
|
|
119
119
|
"tsx": "4.21.0",
|
|
120
120
|
"typedoc": "0.28.19",
|
|
@@ -122,9 +122,9 @@
|
|
|
122
122
|
"typescript": "5.9.3",
|
|
123
123
|
"vite": "8.0.10",
|
|
124
124
|
"vitest": "4.1.5",
|
|
125
|
-
"zod": "4.3
|
|
125
|
+
"zod": "4.4.3"
|
|
126
126
|
},
|
|
127
|
-
"packageManager": "pnpm@10.33.
|
|
127
|
+
"packageManager": "pnpm@10.33.4",
|
|
128
128
|
"engines": {
|
|
129
129
|
"node": ">=22.18.0",
|
|
130
130
|
"pnpm": ">=9.0.0"
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Arr, memoizeFunction, Result } from 'ts-data-forge';
|
|
2
|
+
import { type ArrayAtMostLen, type SmallUint } from 'ts-type-forge';
|
|
3
|
+
import { type Type } from '../type.mjs';
|
|
4
|
+
import {
|
|
5
|
+
createAssertFn,
|
|
6
|
+
createCastFn,
|
|
7
|
+
createIsFn,
|
|
8
|
+
createPrimitiveValidationError,
|
|
9
|
+
prependIndexToValidationErrors,
|
|
10
|
+
type ValidationError,
|
|
11
|
+
} from '../utils/index.mjs';
|
|
12
|
+
|
|
13
|
+
export type { ArrayAtMostLen } from 'ts-type-forge';
|
|
14
|
+
|
|
15
|
+
export const arrayAtMostLength = <A, N extends SmallUint>(
|
|
16
|
+
size: N,
|
|
17
|
+
elementType: Type<A>,
|
|
18
|
+
options?: Partial<
|
|
19
|
+
Readonly<{
|
|
20
|
+
typeName: string;
|
|
21
|
+
defaultValue: ArrayAtMostLen<N, A>;
|
|
22
|
+
}>
|
|
23
|
+
>,
|
|
24
|
+
): Type<ArrayAtMostLen<N, A>> => {
|
|
25
|
+
type T = ArrayAtMostLen<N, A>;
|
|
26
|
+
|
|
27
|
+
const typeName =
|
|
28
|
+
options?.typeName ?? `ArrayAtMostLen<${size}, ${elementType.typeName}>`;
|
|
29
|
+
|
|
30
|
+
const getDefaultValue = memoizeFunction(
|
|
31
|
+
(): T =>
|
|
32
|
+
options?.defaultValue ??
|
|
33
|
+
// The empty array is the shortest value satisfying `length <= size`.
|
|
34
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
35
|
+
(Arr.create(0, elementType.defaultValue) as T),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const validate: Type<T>['validate'] = (a) => {
|
|
39
|
+
if (!Arr.isArray(a)) {
|
|
40
|
+
return Result.err([
|
|
41
|
+
createPrimitiveValidationError({
|
|
42
|
+
actualValue: a,
|
|
43
|
+
expectedType: 'array',
|
|
44
|
+
typeName,
|
|
45
|
+
details: undefined,
|
|
46
|
+
}),
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (a.length > size) {
|
|
51
|
+
return Result.err([
|
|
52
|
+
{
|
|
53
|
+
path: [],
|
|
54
|
+
actualValue: a,
|
|
55
|
+
expectedType: typeName,
|
|
56
|
+
typeName,
|
|
57
|
+
details: {
|
|
58
|
+
kind: 'array-max-length',
|
|
59
|
+
maxLength: size,
|
|
60
|
+
actualLength: a.length,
|
|
61
|
+
},
|
|
62
|
+
} satisfies ValidationError,
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const errors: readonly ValidationError[] = Arr.generate(function* () {
|
|
67
|
+
for (const [index, el] of a.entries()) {
|
|
68
|
+
const res = elementType.validate(el);
|
|
69
|
+
|
|
70
|
+
if (Result.isErr(res)) {
|
|
71
|
+
yield* prependIndexToValidationErrors(res.value, index);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (Arr.isNonEmpty(errors)) {
|
|
77
|
+
return Result.err(errors);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
81
|
+
return Result.ok(a as unknown as T);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const fill: Type<T>['fill'] = (a) =>
|
|
85
|
+
Arr.isArray(a)
|
|
86
|
+
? // Keep the input but trim down to at most `size` elements.
|
|
87
|
+
// TODO: remove as
|
|
88
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
89
|
+
(Arr.map(
|
|
90
|
+
Arr.take(a, size),
|
|
91
|
+
(el) => elementType.fill(el) satisfies A,
|
|
92
|
+
) as T)
|
|
93
|
+
: getDefaultValue();
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
typeName,
|
|
97
|
+
get defaultValue() {
|
|
98
|
+
return getDefaultValue();
|
|
99
|
+
},
|
|
100
|
+
fill,
|
|
101
|
+
validate,
|
|
102
|
+
is: createIsFn(validate),
|
|
103
|
+
cast: createCastFn(validate),
|
|
104
|
+
assertIs: createAssertFn(validate),
|
|
105
|
+
};
|
|
106
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { expectType, Result } from 'ts-data-forge';
|
|
2
|
+
import { type ArrayAtMostLen } from 'ts-type-forge';
|
|
3
|
+
import { number } from '../primitives/index.mjs';
|
|
4
|
+
import { type TypeOf } from '../type.mjs';
|
|
5
|
+
import {
|
|
6
|
+
type ValidationError,
|
|
7
|
+
validationErrorsToMessages,
|
|
8
|
+
} from '../utils/index.mjs';
|
|
9
|
+
import { arrayAtMostLength } from './array-at-most-length.mjs';
|
|
10
|
+
|
|
11
|
+
describe(arrayAtMostLength, () => {
|
|
12
|
+
describe('arg patterns', () => {
|
|
13
|
+
test('without explicit default value', () => {
|
|
14
|
+
assert.deepStrictEqual(arrayAtMostLength(3, number()).defaultValue, []);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('with explicit default value override', () => {
|
|
18
|
+
assert.deepStrictEqual(
|
|
19
|
+
arrayAtMostLength(3, number(), {
|
|
20
|
+
typeName: 'ys',
|
|
21
|
+
defaultValue: [1, 2, 3],
|
|
22
|
+
}).defaultValue,
|
|
23
|
+
[1, 2, 3],
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const xs = arrayAtMostLength(3, number(), {
|
|
29
|
+
typeName: 'xs',
|
|
30
|
+
defaultValue: [1, 2, 3],
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
type Xs = TypeOf<typeof xs>;
|
|
34
|
+
|
|
35
|
+
expectType<Xs, ArrayAtMostLen<3, number>>('=');
|
|
36
|
+
|
|
37
|
+
expectType<typeof xs.defaultValue, Xs>('=');
|
|
38
|
+
|
|
39
|
+
describe('is', () => {
|
|
40
|
+
test('truthy case (max length)', () => {
|
|
41
|
+
const ys: unknown = [4, 5, 6] as const;
|
|
42
|
+
|
|
43
|
+
if (xs.is(ys)) {
|
|
44
|
+
expectType<typeof ys, Xs>('=');
|
|
45
|
+
} else {
|
|
46
|
+
expectType<typeof ys, unknown>('=');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
assert.isTrue(xs.is(ys));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('truthy case (empty)', () => {
|
|
53
|
+
const ys: unknown = [] as const;
|
|
54
|
+
|
|
55
|
+
assert.isTrue(xs.is(ys));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('falsy case 1 (too long)', () => {
|
|
59
|
+
const ys: unknown = [1, 2, 3, 4] as const;
|
|
60
|
+
|
|
61
|
+
assert.isFalse(xs.is(ys));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('falsy case 2 (wrong element type)', () => {
|
|
65
|
+
const ys: unknown = [1, '2', 3] as const;
|
|
66
|
+
|
|
67
|
+
assert.isFalse(xs.is(ys));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('falsy case 3 (not an array)', () => {
|
|
71
|
+
const ys: unknown = 'foo';
|
|
72
|
+
|
|
73
|
+
assert.isFalse(xs.is(ys));
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('validate', () => {
|
|
78
|
+
test('truthy case', () => {
|
|
79
|
+
const ys: unknown = [4, 5] as const;
|
|
80
|
+
|
|
81
|
+
const result = xs.validate(ys);
|
|
82
|
+
|
|
83
|
+
expectType<typeof result, Result<Xs, readonly ValidationError[]>>('=');
|
|
84
|
+
|
|
85
|
+
assert.isTrue(Result.isOk(result));
|
|
86
|
+
|
|
87
|
+
const resultValue = Result.unwrapThrow(result);
|
|
88
|
+
|
|
89
|
+
assert.deepStrictEqual(resultValue, [4, 5]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('validate returns input as-is for OK cases', () => {
|
|
93
|
+
const input = [4, 5, 6] as const;
|
|
94
|
+
|
|
95
|
+
const result = xs.validate(input);
|
|
96
|
+
|
|
97
|
+
assert.isTrue(Result.isOk(result));
|
|
98
|
+
|
|
99
|
+
const resultValue1 = Result.unwrapThrow(result);
|
|
100
|
+
|
|
101
|
+
expect(resultValue1).toBe(input); // ✅ same reference
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('falsy case 1 (not an array)', () => {
|
|
105
|
+
const ys: unknown = 'foo';
|
|
106
|
+
|
|
107
|
+
const result = xs.validate(ys);
|
|
108
|
+
|
|
109
|
+
assert.isTrue(Result.isErr(result));
|
|
110
|
+
|
|
111
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
112
|
+
|
|
113
|
+
assert.deepStrictEqual(resultError, [
|
|
114
|
+
{
|
|
115
|
+
path: [],
|
|
116
|
+
actualValue: ys,
|
|
117
|
+
expectedType: 'array',
|
|
118
|
+
typeName: 'xs',
|
|
119
|
+
details: undefined,
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
124
|
+
'Error: expected <array> type but <string> type value "foo" was passed.',
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('falsy case 2 (too long)', () => {
|
|
129
|
+
const ys: unknown = [1, 2, 3, 4] as const;
|
|
130
|
+
|
|
131
|
+
const result = xs.validate(ys);
|
|
132
|
+
|
|
133
|
+
assert.isTrue(Result.isErr(result));
|
|
134
|
+
|
|
135
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
136
|
+
|
|
137
|
+
assert.deepStrictEqual(resultError, [
|
|
138
|
+
{
|
|
139
|
+
path: [],
|
|
140
|
+
actualValue: ys,
|
|
141
|
+
expectedType: 'xs',
|
|
142
|
+
typeName: 'xs',
|
|
143
|
+
details: {
|
|
144
|
+
kind: 'array-max-length',
|
|
145
|
+
maxLength: 3,
|
|
146
|
+
actualLength: 4,
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
152
|
+
'Error: expected array of length 3 or less but length 4 was passed.',
|
|
153
|
+
]);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('falsy case 3 (wrong element type)', () => {
|
|
157
|
+
const ys: unknown = [1, '2', 3] as const;
|
|
158
|
+
|
|
159
|
+
const result = xs.validate(ys);
|
|
160
|
+
|
|
161
|
+
assert.isTrue(Result.isErr(result));
|
|
162
|
+
|
|
163
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
164
|
+
|
|
165
|
+
assert.deepStrictEqual(resultError, [
|
|
166
|
+
{
|
|
167
|
+
path: ['1'],
|
|
168
|
+
actualValue: '2',
|
|
169
|
+
expectedType: 'number',
|
|
170
|
+
typeName: 'number',
|
|
171
|
+
details: undefined,
|
|
172
|
+
},
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
176
|
+
'Error at 1: expected <number> type but <string> type value "2" was passed.',
|
|
177
|
+
]);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('fill', () => {
|
|
182
|
+
test('keeps numeric entries and trims extras to max', () => {
|
|
183
|
+
const ys: unknown = [4, 5, 6, 7] as const;
|
|
184
|
+
|
|
185
|
+
assert.deepStrictEqual(xs.fill(ys), [4, 5, 6]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test('keeps shorter arrays as-is and fills invalid entries', () => {
|
|
189
|
+
const ys: unknown = [4, '5'] as const;
|
|
190
|
+
|
|
191
|
+
assert.deepStrictEqual(xs.fill(ys), [4, 0]);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('keeps the empty array', () => {
|
|
195
|
+
const ys: unknown = [] as const;
|
|
196
|
+
|
|
197
|
+
assert.deepStrictEqual(xs.fill(ys), []);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('fill with the default value for non-array input', () => {
|
|
201
|
+
const ys: unknown = null;
|
|
202
|
+
|
|
203
|
+
assert.deepStrictEqual(xs.fill(ys), [1, 2, 3]);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Arr, memoizeFunction, Result } from 'ts-data-forge';
|
|
2
|
+
import { type ArrayBoundedLen, type SmallUint } from 'ts-type-forge';
|
|
3
|
+
import { type Type } from '../type.mjs';
|
|
4
|
+
import {
|
|
5
|
+
createAssertFn,
|
|
6
|
+
createCastFn,
|
|
7
|
+
createIsFn,
|
|
8
|
+
createPrimitiveValidationError,
|
|
9
|
+
prependIndexToValidationErrors,
|
|
10
|
+
type ValidationError,
|
|
11
|
+
} from '../utils/index.mjs';
|
|
12
|
+
|
|
13
|
+
export type { ArrayBoundedLen } from 'ts-type-forge';
|
|
14
|
+
|
|
15
|
+
export const arrayBoundedLength = <
|
|
16
|
+
A,
|
|
17
|
+
Min extends SmallUint,
|
|
18
|
+
Max extends SmallUint,
|
|
19
|
+
>(
|
|
20
|
+
min: Min,
|
|
21
|
+
max: Max,
|
|
22
|
+
elementType: Type<A>,
|
|
23
|
+
options?: Partial<
|
|
24
|
+
Readonly<{
|
|
25
|
+
typeName: string;
|
|
26
|
+
defaultValue: ArrayBoundedLen<Min, Max, A>;
|
|
27
|
+
}>
|
|
28
|
+
>,
|
|
29
|
+
): Type<ArrayBoundedLen<Min, Max, A>> => {
|
|
30
|
+
type T = ArrayBoundedLen<Min, Max, A>;
|
|
31
|
+
|
|
32
|
+
const typeName =
|
|
33
|
+
options?.typeName ??
|
|
34
|
+
`ArrayBoundedLen<${min}, ${max}, ${elementType.typeName}>`;
|
|
35
|
+
|
|
36
|
+
const getDefaultValue = memoizeFunction(
|
|
37
|
+
(): T =>
|
|
38
|
+
options?.defaultValue ??
|
|
39
|
+
// An array of the minimum length is the shortest value within the range.
|
|
40
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
41
|
+
(Arr.create(min, elementType.defaultValue) as T),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const validate: Type<T>['validate'] = (a) => {
|
|
45
|
+
if (!Arr.isArray(a)) {
|
|
46
|
+
return Result.err([
|
|
47
|
+
createPrimitiveValidationError({
|
|
48
|
+
actualValue: a,
|
|
49
|
+
expectedType: 'array',
|
|
50
|
+
typeName,
|
|
51
|
+
details: undefined,
|
|
52
|
+
}),
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (a.length < min || max < a.length) {
|
|
57
|
+
return Result.err([
|
|
58
|
+
{
|
|
59
|
+
path: [],
|
|
60
|
+
actualValue: a,
|
|
61
|
+
expectedType: typeName,
|
|
62
|
+
typeName,
|
|
63
|
+
details: {
|
|
64
|
+
kind: 'array-range-length',
|
|
65
|
+
minLength: min,
|
|
66
|
+
maxLength: max,
|
|
67
|
+
actualLength: a.length,
|
|
68
|
+
},
|
|
69
|
+
} satisfies ValidationError,
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const errors: readonly ValidationError[] = Arr.generate(function* () {
|
|
74
|
+
for (const [index, el] of a.entries()) {
|
|
75
|
+
const res = elementType.validate(el);
|
|
76
|
+
|
|
77
|
+
if (Result.isErr(res)) {
|
|
78
|
+
yield* prependIndexToValidationErrors(res.value, index);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (Arr.isNonEmpty(errors)) {
|
|
84
|
+
return Result.err(errors);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
88
|
+
return Result.ok(a as unknown as T);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const fill: Type<T>['fill'] = (a) => {
|
|
92
|
+
if (!Arr.isArray(a)) {
|
|
93
|
+
return getDefaultValue();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Trim down to at most `max`, then pad up to at least `min`.
|
|
97
|
+
const capped = Arr.take(a, max);
|
|
98
|
+
|
|
99
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
100
|
+
return (
|
|
101
|
+
capped.length >= min
|
|
102
|
+
? Arr.map(capped, (el) => elementType.fill(el) satisfies A)
|
|
103
|
+
: Arr.map(Arr.seq(min), (i) => elementType.fill(capped[i]) satisfies A)
|
|
104
|
+
) as T;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
typeName,
|
|
109
|
+
get defaultValue() {
|
|
110
|
+
return getDefaultValue();
|
|
111
|
+
},
|
|
112
|
+
fill,
|
|
113
|
+
validate,
|
|
114
|
+
is: createIsFn(validate),
|
|
115
|
+
cast: createCastFn(validate),
|
|
116
|
+
assertIs: createAssertFn(validate),
|
|
117
|
+
};
|
|
118
|
+
};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { expectType, Result } from 'ts-data-forge';
|
|
2
|
+
import { type ArrayBoundedLen } from 'ts-type-forge';
|
|
3
|
+
import { number } from '../primitives/index.mjs';
|
|
4
|
+
import { type TypeOf } from '../type.mjs';
|
|
5
|
+
import {
|
|
6
|
+
type ValidationError,
|
|
7
|
+
validationErrorsToMessages,
|
|
8
|
+
} from '../utils/index.mjs';
|
|
9
|
+
import { arrayBoundedLength } from './array-bounded-length.mjs';
|
|
10
|
+
|
|
11
|
+
describe(arrayBoundedLength, () => {
|
|
12
|
+
describe('arg patterns', () => {
|
|
13
|
+
test('without explicit default value', () => {
|
|
14
|
+
assert.deepStrictEqual(
|
|
15
|
+
arrayBoundedLength(2, 4, number()).defaultValue,
|
|
16
|
+
[0, 0],
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('with explicit element default value', () => {
|
|
21
|
+
assert.deepStrictEqual(
|
|
22
|
+
arrayBoundedLength(2, 4, number(5)).defaultValue,
|
|
23
|
+
[5, 5],
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('with explicit default value override', () => {
|
|
28
|
+
assert.deepStrictEqual(
|
|
29
|
+
arrayBoundedLength(2, 4, number(), {
|
|
30
|
+
typeName: 'ys',
|
|
31
|
+
defaultValue: [1, 2, 3],
|
|
32
|
+
}).defaultValue,
|
|
33
|
+
[1, 2, 3],
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const xs = arrayBoundedLength(2, 4, number(), {
|
|
39
|
+
typeName: 'xs',
|
|
40
|
+
defaultValue: [1, 2, 3],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
type Xs = TypeOf<typeof xs>;
|
|
44
|
+
|
|
45
|
+
expectType<Xs, ArrayBoundedLen<2, 4, number>>('=');
|
|
46
|
+
|
|
47
|
+
expectType<typeof xs.defaultValue, Xs>('=');
|
|
48
|
+
|
|
49
|
+
describe('is', () => {
|
|
50
|
+
test('truthy case (min length)', () => {
|
|
51
|
+
const ys: unknown = [4, 5] as const;
|
|
52
|
+
|
|
53
|
+
if (xs.is(ys)) {
|
|
54
|
+
expectType<typeof ys, Xs>('=');
|
|
55
|
+
} else {
|
|
56
|
+
expectType<typeof ys, unknown>('=');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
assert.isTrue(xs.is(ys));
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('truthy case (max length)', () => {
|
|
63
|
+
const ys: unknown = [4, 5, 6, 7] as const;
|
|
64
|
+
|
|
65
|
+
assert.isTrue(xs.is(ys));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('falsy case 1 (too short)', () => {
|
|
69
|
+
const ys: unknown = [4] as const;
|
|
70
|
+
|
|
71
|
+
assert.isFalse(xs.is(ys));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('falsy case 2 (too long)', () => {
|
|
75
|
+
const ys: unknown = [1, 2, 3, 4, 5] as const;
|
|
76
|
+
|
|
77
|
+
assert.isFalse(xs.is(ys));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('falsy case 3 (wrong element type)', () => {
|
|
81
|
+
const ys: unknown = [1, '2'] as const;
|
|
82
|
+
|
|
83
|
+
assert.isFalse(xs.is(ys));
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('falsy case 4 (not an array)', () => {
|
|
87
|
+
const ys: unknown = 'foo';
|
|
88
|
+
|
|
89
|
+
assert.isFalse(xs.is(ys));
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('validate', () => {
|
|
94
|
+
test('truthy case', () => {
|
|
95
|
+
const ys: unknown = [4, 5, 6] as const;
|
|
96
|
+
|
|
97
|
+
const result = xs.validate(ys);
|
|
98
|
+
|
|
99
|
+
expectType<typeof result, Result<Xs, readonly ValidationError[]>>('=');
|
|
100
|
+
|
|
101
|
+
assert.isTrue(Result.isOk(result));
|
|
102
|
+
|
|
103
|
+
const resultValue = Result.unwrapThrow(result);
|
|
104
|
+
|
|
105
|
+
assert.deepStrictEqual(resultValue, [4, 5, 6]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('validate returns input as-is for OK cases', () => {
|
|
109
|
+
const input = [4, 5, 6] as const;
|
|
110
|
+
|
|
111
|
+
const result = xs.validate(input);
|
|
112
|
+
|
|
113
|
+
assert.isTrue(Result.isOk(result));
|
|
114
|
+
|
|
115
|
+
const resultValue1 = Result.unwrapThrow(result);
|
|
116
|
+
|
|
117
|
+
expect(resultValue1).toBe(input); // ✅ same reference
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('falsy case 1 (not an array)', () => {
|
|
121
|
+
const ys: unknown = 'foo';
|
|
122
|
+
|
|
123
|
+
const result = xs.validate(ys);
|
|
124
|
+
|
|
125
|
+
assert.isTrue(Result.isErr(result));
|
|
126
|
+
|
|
127
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
128
|
+
|
|
129
|
+
assert.deepStrictEqual(resultError, [
|
|
130
|
+
{
|
|
131
|
+
path: [],
|
|
132
|
+
actualValue: ys,
|
|
133
|
+
expectedType: 'array',
|
|
134
|
+
typeName: 'xs',
|
|
135
|
+
details: undefined,
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
140
|
+
'Error: expected <array> type but <string> type value "foo" was passed.',
|
|
141
|
+
]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('falsy case 2 (too short)', () => {
|
|
145
|
+
const ys: unknown = [4] as const;
|
|
146
|
+
|
|
147
|
+
const result = xs.validate(ys);
|
|
148
|
+
|
|
149
|
+
assert.isTrue(Result.isErr(result));
|
|
150
|
+
|
|
151
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
152
|
+
|
|
153
|
+
assert.deepStrictEqual(resultError, [
|
|
154
|
+
{
|
|
155
|
+
path: [],
|
|
156
|
+
actualValue: ys,
|
|
157
|
+
expectedType: 'xs',
|
|
158
|
+
typeName: 'xs',
|
|
159
|
+
details: {
|
|
160
|
+
kind: 'array-range-length',
|
|
161
|
+
minLength: 2,
|
|
162
|
+
maxLength: 4,
|
|
163
|
+
actualLength: 1,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
169
|
+
'Error: expected array of length between 2 and 4 but length 1 was passed.',
|
|
170
|
+
]);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('falsy case 3 (too long)', () => {
|
|
174
|
+
const ys: unknown = [1, 2, 3, 4, 5] as const;
|
|
175
|
+
|
|
176
|
+
const result = xs.validate(ys);
|
|
177
|
+
|
|
178
|
+
assert.isTrue(Result.isErr(result));
|
|
179
|
+
|
|
180
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
181
|
+
|
|
182
|
+
assert.deepStrictEqual(resultError, [
|
|
183
|
+
{
|
|
184
|
+
path: [],
|
|
185
|
+
actualValue: ys,
|
|
186
|
+
expectedType: 'xs',
|
|
187
|
+
typeName: 'xs',
|
|
188
|
+
details: {
|
|
189
|
+
kind: 'array-range-length',
|
|
190
|
+
minLength: 2,
|
|
191
|
+
maxLength: 4,
|
|
192
|
+
actualLength: 5,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
198
|
+
'Error: expected array of length between 2 and 4 but length 5 was passed.',
|
|
199
|
+
]);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('falsy case 4 (wrong element type)', () => {
|
|
203
|
+
const ys: unknown = [1, '2'] as const;
|
|
204
|
+
|
|
205
|
+
const result = xs.validate(ys);
|
|
206
|
+
|
|
207
|
+
assert.isTrue(Result.isErr(result));
|
|
208
|
+
|
|
209
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
210
|
+
|
|
211
|
+
assert.deepStrictEqual(resultError, [
|
|
212
|
+
{
|
|
213
|
+
path: ['1'],
|
|
214
|
+
actualValue: '2',
|
|
215
|
+
expectedType: 'number',
|
|
216
|
+
typeName: 'number',
|
|
217
|
+
details: undefined,
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
|
|
221
|
+
assert.deepStrictEqual(validationErrorsToMessages(resultError), [
|
|
222
|
+
'Error at 1: expected <number> type but <string> type value "2" was passed.',
|
|
223
|
+
]);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe('fill', () => {
|
|
228
|
+
test('trims extras down to max', () => {
|
|
229
|
+
const ys: unknown = [4, 5, 6, 7, 8] as const;
|
|
230
|
+
|
|
231
|
+
assert.deepStrictEqual(xs.fill(ys), [4, 5, 6, 7]);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test('pads up to min and fills invalid entries', () => {
|
|
235
|
+
const ys: unknown = [4] as const;
|
|
236
|
+
|
|
237
|
+
assert.deepStrictEqual(xs.fill(ys), [4, 0]);
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
test('keeps in-range arrays and fills invalid entries', () => {
|
|
241
|
+
const ys: unknown = [4, '5', 6] as const;
|
|
242
|
+
|
|
243
|
+
assert.deepStrictEqual(xs.fill(ys), [4, 0, 6]);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test('fill with the default value for non-array input', () => {
|
|
247
|
+
const ys: unknown = null;
|
|
248
|
+
|
|
249
|
+
assert.deepStrictEqual(xs.fill(ys), [1, 2, 3]);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
});
|
package/src/array/index.mts
CHANGED
|
@@ -32,6 +32,17 @@ export type ValidationErrorDetails = Readonly<
|
|
|
32
32
|
minLength: number;
|
|
33
33
|
actualLength: number;
|
|
34
34
|
}
|
|
35
|
+
| {
|
|
36
|
+
kind: 'array-max-length';
|
|
37
|
+
maxLength: number;
|
|
38
|
+
actualLength: number;
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
kind: 'array-range-length';
|
|
42
|
+
minLength: number;
|
|
43
|
+
maxLength: number;
|
|
44
|
+
actualLength: number;
|
|
45
|
+
}
|
|
35
46
|
| {
|
|
36
47
|
kind: 'non-empty-array';
|
|
37
48
|
}
|
|
@@ -156,6 +167,12 @@ const createDetailsMessage = (
|
|
|
156
167
|
case 'array-min-length':
|
|
157
168
|
return `expected array of length ${error.details.minLength} or more but length ${error.details.actualLength} was passed.`;
|
|
158
169
|
|
|
170
|
+
case 'array-max-length':
|
|
171
|
+
return `expected array of length ${error.details.maxLength} or less but length ${error.details.actualLength} was passed.`;
|
|
172
|
+
|
|
173
|
+
case 'array-range-length':
|
|
174
|
+
return `expected array of length between ${error.details.minLength} and ${error.details.maxLength} but length ${error.details.actualLength} was passed.`;
|
|
175
|
+
|
|
159
176
|
case 'non-empty-array':
|
|
160
177
|
return 'expected non-empty array but empty array was passed.';
|
|
161
178
|
|