ts-fortress 5.0.0 → 5.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 +1 -0
- package/dist/array/array-at-least-length.d.mts +6 -0
- package/dist/array/array-at-least-length.d.mts.map +1 -0
- package/dist/array/array-at-least-length.mjs +63 -0
- package/dist/array/array-at-least-length.mjs.map +1 -0
- package/dist/array/index.d.mts +1 -0
- package/dist/array/index.d.mts.map +1 -1
- package/dist/array/index.mjs +1 -0
- package/dist/array/index.mjs.map +1 -1
- package/dist/entry-point.mjs +1 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/array/array-at-least-length.mts +85 -0
- package/src/array/array-at-least-length.test.mts +197 -0
- package/src/array/index.mts +1 -0
- package/src/other-types/literal.test.mts +1 -1
package/README.md
CHANGED
|
@@ -910,6 +910,7 @@ type ValidationError = Readonly<{
|
|
|
910
910
|
- `t.nonEmptyArray(elementType)` - Non-empty array validation
|
|
911
911
|
- `t.tuple([t1, t2, ..., tN])` - Fixed-length tuple validation
|
|
912
912
|
- `t.arrayOfLength(size, elementType)` - Fixed-length array validation
|
|
913
|
+
- `t.arrayAtLeastLength(size, elementType)` - Array validation with a minimum length
|
|
913
914
|
|
|
914
915
|
### Objects
|
|
915
916
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type Type } from '../type.mjs';
|
|
2
|
+
export declare const arrayAtLeastLength: <A, N extends SmallUint>(size: N, elementType: Type<A>, options?: PartialReadonly<{
|
|
3
|
+
typeName: string;
|
|
4
|
+
defaultValue: ArrayAtLeastLen<N, A>;
|
|
5
|
+
}>) => Type<ArrayAtLeastLen<N, A>>;
|
|
6
|
+
//# sourceMappingURL=array-at-least-length.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array-at-least-length.d.mts","sourceRoot":"","sources":["../../src/array/array-at-least-length.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAWxC,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,CAAC,SAAS,SAAS,EACvD,MAAM,CAAC,EACP,aAAa,IAAI,CAAC,CAAC,CAAC,EACpB,UAAU,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACrC,CAAC,KACD,IAAI,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAiE5B,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { 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 arrayAtLeastLength = (size, elementType, options) => {
|
|
8
|
+
const { typeName = `ArrayAtLeastLen<${size}, ${elementType.typeName}>`,
|
|
9
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
10
|
+
defaultValue = Arr.create(size, elementType.defaultValue), } = options ?? {};
|
|
11
|
+
const validate = (a) => {
|
|
12
|
+
if (!Arr.isArray(a)) {
|
|
13
|
+
return Result.err([
|
|
14
|
+
createPrimitiveValidationError({
|
|
15
|
+
actualValue: a,
|
|
16
|
+
expectedType: 'array',
|
|
17
|
+
typeName,
|
|
18
|
+
}),
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
if (a.length < size) {
|
|
22
|
+
return Result.err([
|
|
23
|
+
{
|
|
24
|
+
path: [],
|
|
25
|
+
actualValue: a,
|
|
26
|
+
expectedType: typeName,
|
|
27
|
+
message: `Expected array of length ${size} or more, got length ${a.length}`,
|
|
28
|
+
typeName,
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
32
|
+
const errors = Arr.generate(function* () {
|
|
33
|
+
for (const [index, el] of a.entries()) {
|
|
34
|
+
const res = elementType.validate(el);
|
|
35
|
+
if (Result.isErr(res)) {
|
|
36
|
+
yield* prependIndexToValidationErrors(res.value, index);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
if (errors.length > 0) {
|
|
41
|
+
return Result.err(errors);
|
|
42
|
+
}
|
|
43
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
44
|
+
return Result.ok(a);
|
|
45
|
+
};
|
|
46
|
+
const fill = (a) => Arr.isArray(a)
|
|
47
|
+
? // TODO: remove as
|
|
48
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
49
|
+
Arr.map(Arr.seq(size), (i) => elementType.fill(a[i]))
|
|
50
|
+
: defaultValue;
|
|
51
|
+
return {
|
|
52
|
+
typeName,
|
|
53
|
+
defaultValue,
|
|
54
|
+
fill,
|
|
55
|
+
validate,
|
|
56
|
+
is: createIsFn(validate),
|
|
57
|
+
cast: createCastFn(validate),
|
|
58
|
+
assertIs: createAssertFn(validate),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export { arrayAtLeastLength };
|
|
63
|
+
//# sourceMappingURL=array-at-least-length.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array-at-least-length.mjs","sources":["../../src/array/array-at-least-length.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;AAYO,MAAM,kBAAkB,GAAG,CAChC,IAAO,EACP,WAAoB,EACpB,OAGE,KAC6B;IAG/B,MAAM,EACJ,QAAQ,GAAG,CAAA,gBAAA,EAAmB,IAAI,CAAA,EAAA,EAAK,WAAW,CAAC,QAAQ,CAAA,CAAA,CAAG;;AAE9D,IAAA,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,YAAY,CAAM,GAC/D,GAAG,OAAO,IAAI,EAAE;AAEjB,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;iBACT,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;AACtB,oBAAA,OAAO,EAAE,CAAA,yBAAA,EAA4B,IAAI,wBAAwB,CAAC,CAAC,MAAM,CAAA,CAAE;oBAC3E,QAAQ;AAC4B,iBAAA;AACvC,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;AACpC,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,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;AACrB,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;;YAEG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAa;UACjE,YAAY;IAElB,OAAO;QACL,QAAQ;QACR,YAAY;QACZ,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,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,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC"}
|
package/dist/array/index.mjs
CHANGED
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,4 +1,5 @@
|
|
|
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
|
+
export { arrayAtLeastLength } from './array/array-at-least-length.mjs';
|
|
2
3
|
export { arrayOfLength } from './array/array-of-length.mjs';
|
|
3
4
|
export { array } from './array/array.mjs';
|
|
4
5
|
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
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-fortress",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript"
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"z:vitest": "vitest --config ./configs/vitest.config.ts"
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"ts-data-forge": "^3.
|
|
67
|
+
"ts-data-forge": "^3.3.0",
|
|
68
68
|
"ts-type-forge": "^2.2.0"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@semantic-release/github": "^11.0.6",
|
|
80
80
|
"@semantic-release/npm": "^12.0.2",
|
|
81
81
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
82
|
-
"@types/node": "^24.
|
|
82
|
+
"@types/node": "^24.5.2",
|
|
83
83
|
"@vitest/coverage-v8": "^3.2.4",
|
|
84
84
|
"@vitest/ui": "^3.2.4",
|
|
85
85
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
@@ -94,9 +94,9 @@
|
|
|
94
94
|
"prettier": "^3.6.2",
|
|
95
95
|
"prettier-plugin-organize-imports": "^4.2.0",
|
|
96
96
|
"prettier-plugin-packagejson": "^2.5.19",
|
|
97
|
-
"rollup": "^4.
|
|
98
|
-
"semantic-release": "^24.2.
|
|
99
|
-
"ts-repo-utils": "^7.
|
|
97
|
+
"rollup": "^4.52.0",
|
|
98
|
+
"semantic-release": "^24.2.9",
|
|
99
|
+
"ts-repo-utils": "^7.7.0",
|
|
100
100
|
"tslib": "^2.8.1",
|
|
101
101
|
"tsx": "^4.20.5",
|
|
102
102
|
"typedoc": "^0.28.13",
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Arr, Result } from 'ts-data-forge';
|
|
2
|
+
import { type Type } from '../type.mjs';
|
|
3
|
+
import {
|
|
4
|
+
createAssertFn,
|
|
5
|
+
createCastFn,
|
|
6
|
+
createIsFn,
|
|
7
|
+
createPrimitiveValidationError,
|
|
8
|
+
prependIndexToValidationErrors,
|
|
9
|
+
type ValidationError,
|
|
10
|
+
type ValidationErrorWithMessage,
|
|
11
|
+
} from '../utils/index.mjs';
|
|
12
|
+
|
|
13
|
+
export const arrayAtLeastLength = <A, N extends SmallUint>(
|
|
14
|
+
size: N,
|
|
15
|
+
elementType: Type<A>,
|
|
16
|
+
options?: PartialReadonly<{
|
|
17
|
+
typeName: string;
|
|
18
|
+
defaultValue: ArrayAtLeastLen<N, A>;
|
|
19
|
+
}>,
|
|
20
|
+
): Type<ArrayAtLeastLen<N, A>> => {
|
|
21
|
+
type T = ArrayAtLeastLen<N, A>;
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
typeName = `ArrayAtLeastLen<${size}, ${elementType.typeName}>`,
|
|
25
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
26
|
+
defaultValue = Arr.create(size, elementType.defaultValue) as T,
|
|
27
|
+
} = options ?? {};
|
|
28
|
+
|
|
29
|
+
const validate: Type<T>['validate'] = (a) => {
|
|
30
|
+
if (!Arr.isArray(a)) {
|
|
31
|
+
return Result.err([
|
|
32
|
+
createPrimitiveValidationError({
|
|
33
|
+
actualValue: a,
|
|
34
|
+
expectedType: 'array',
|
|
35
|
+
typeName,
|
|
36
|
+
}),
|
|
37
|
+
]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (a.length < size) {
|
|
41
|
+
return Result.err([
|
|
42
|
+
{
|
|
43
|
+
path: [],
|
|
44
|
+
actualValue: a,
|
|
45
|
+
expectedType: typeName,
|
|
46
|
+
message: `Expected array of length ${size} or more, got length ${a.length}`,
|
|
47
|
+
typeName,
|
|
48
|
+
} satisfies ValidationErrorWithMessage,
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const errors: readonly ValidationError[] = Arr.generate(function* () {
|
|
53
|
+
for (const [index, el] of a.entries()) {
|
|
54
|
+
const res = elementType.validate(el);
|
|
55
|
+
if (Result.isErr(res)) {
|
|
56
|
+
yield* prependIndexToValidationErrors(res.value, index);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (errors.length > 0) {
|
|
62
|
+
return Result.err(errors);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
66
|
+
return Result.ok(a as unknown as T);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const fill: Type<T>['fill'] = (a) =>
|
|
70
|
+
Arr.isArray(a)
|
|
71
|
+
? // TODO: remove as
|
|
72
|
+
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
73
|
+
(Arr.map(Arr.seq(size), (i) => elementType.fill(a[i]) satisfies A) as T)
|
|
74
|
+
: defaultValue;
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
typeName,
|
|
78
|
+
defaultValue,
|
|
79
|
+
fill,
|
|
80
|
+
validate,
|
|
81
|
+
is: createIsFn(validate),
|
|
82
|
+
cast: createCastFn(validate),
|
|
83
|
+
assertIs: createAssertFn(validate),
|
|
84
|
+
};
|
|
85
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { expectType, Result } from 'ts-data-forge';
|
|
2
|
+
import { number } from '../primitives/index.mjs';
|
|
3
|
+
import { type TypeOf } from '../type.mjs';
|
|
4
|
+
import {
|
|
5
|
+
type ValidationError,
|
|
6
|
+
validationErrorsToMessages,
|
|
7
|
+
} from '../utils/index.mjs';
|
|
8
|
+
import { arrayAtLeastLength } from './array-at-least-length.mjs';
|
|
9
|
+
|
|
10
|
+
describe('arrayAtLeastLength', () => {
|
|
11
|
+
describe('arg patterns', () => {
|
|
12
|
+
test('without explicit default value', () => {
|
|
13
|
+
expect(arrayAtLeastLength(3, number()).defaultValue).toStrictEqual([0, 0, 0]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('with explicit element default value', () => {
|
|
17
|
+
expect(arrayAtLeastLength(2, number(5)).defaultValue).toStrictEqual([5, 5]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('with explicit default value override', () => {
|
|
21
|
+
expect(
|
|
22
|
+
arrayAtLeastLength(3, number(), {
|
|
23
|
+
typeName: 'ys',
|
|
24
|
+
defaultValue: [1, 2, 3, 4],
|
|
25
|
+
}).defaultValue,
|
|
26
|
+
).toStrictEqual([1, 2, 3, 4]);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const xs = arrayAtLeastLength(3, number(), {
|
|
31
|
+
typeName: 'xs',
|
|
32
|
+
defaultValue: [1, 2, 3],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
type Xs = TypeOf<typeof xs>;
|
|
36
|
+
|
|
37
|
+
expectType<Xs, ArrayAtLeastLen<3, number>>('=');
|
|
38
|
+
|
|
39
|
+
expectType<typeof xs.defaultValue, Xs>('=');
|
|
40
|
+
|
|
41
|
+
describe('is', () => {
|
|
42
|
+
test('truthy case', () => {
|
|
43
|
+
const ys: unknown = [4, 5, 6, 7];
|
|
44
|
+
|
|
45
|
+
if (xs.is(ys)) {
|
|
46
|
+
expectType<typeof ys, Xs>('=');
|
|
47
|
+
} else {
|
|
48
|
+
expectType<typeof ys, unknown>('=');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
expect(xs.is(ys)).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('falsy case 1', () => {
|
|
55
|
+
const ys: unknown = [1, 2];
|
|
56
|
+
|
|
57
|
+
if (xs.is(ys)) {
|
|
58
|
+
expectType<typeof ys, Xs>('=');
|
|
59
|
+
} else {
|
|
60
|
+
expectType<typeof ys, unknown>('=');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
expect(xs.is(ys)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('falsy case 2', () => {
|
|
67
|
+
const ys: unknown = [1, '2', 3];
|
|
68
|
+
|
|
69
|
+
if (xs.is(ys)) {
|
|
70
|
+
expectType<typeof ys, Xs>('=');
|
|
71
|
+
} else {
|
|
72
|
+
expectType<typeof ys, unknown>('=');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
expect(xs.is(ys)).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('falsy case 3', () => {
|
|
79
|
+
const ys: unknown = 'foo';
|
|
80
|
+
|
|
81
|
+
if (xs.is(ys)) {
|
|
82
|
+
expectType<typeof ys, Xs>('=');
|
|
83
|
+
} else {
|
|
84
|
+
expectType<typeof ys, unknown>('=');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
expect(xs.is(ys)).toBe(false);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('validate', () => {
|
|
92
|
+
test('truthy case', () => {
|
|
93
|
+
const ys: unknown = [4, 5, 6, 7];
|
|
94
|
+
|
|
95
|
+
const result = xs.validate(ys);
|
|
96
|
+
expectType<typeof result, Result<Xs, readonly ValidationError[]>>('=');
|
|
97
|
+
expect(Result.isOk(result)).toBe(true);
|
|
98
|
+
|
|
99
|
+
const resultValue = Result.unwrapThrow(result);
|
|
100
|
+
expect(resultValue).toStrictEqual([4, 5, 6, 7]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('validate returns input as-is for OK cases', () => {
|
|
104
|
+
const input = [4, 5, 6];
|
|
105
|
+
const result = xs.validate(input);
|
|
106
|
+
expect(Result.isOk(result)).toBe(true);
|
|
107
|
+
const resultValue1 = Result.unwrapThrow(result);
|
|
108
|
+
expect(resultValue1).toBe(input); // ✅ same reference
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('falsy case 1', () => {
|
|
112
|
+
const ys: unknown = 'foo';
|
|
113
|
+
|
|
114
|
+
const result = xs.validate(ys);
|
|
115
|
+
expect(Result.isErr(result)).toBe(true);
|
|
116
|
+
|
|
117
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
118
|
+
expect(resultError).toStrictEqual([
|
|
119
|
+
{
|
|
120
|
+
path: [],
|
|
121
|
+
actualValue: ys,
|
|
122
|
+
expectedType: 'array',
|
|
123
|
+
typeName: 'xs',
|
|
124
|
+
message: undefined,
|
|
125
|
+
},
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
expect(validationErrorsToMessages(resultError)).toStrictEqual([
|
|
129
|
+
'Expected <array>, got <string> type value "foo".',
|
|
130
|
+
]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('falsy case 2', () => {
|
|
134
|
+
const ys: unknown = [1, 2];
|
|
135
|
+
|
|
136
|
+
const result = xs.validate(ys);
|
|
137
|
+
expect(Result.isErr(result)).toBe(true);
|
|
138
|
+
|
|
139
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
140
|
+
expect(resultError).toStrictEqual([
|
|
141
|
+
{
|
|
142
|
+
path: [],
|
|
143
|
+
actualValue: ys,
|
|
144
|
+
expectedType: 'xs',
|
|
145
|
+
typeName: 'xs',
|
|
146
|
+
message: 'Expected array of length 3 or more, got length 2',
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
expect(validationErrorsToMessages(resultError)).toStrictEqual([
|
|
151
|
+
'Expected array of length 3 or more, got length 2',
|
|
152
|
+
]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('falsy case 3', () => {
|
|
156
|
+
const ys: unknown = [1, '2', 3];
|
|
157
|
+
|
|
158
|
+
const result = xs.validate(ys);
|
|
159
|
+
expect(Result.isErr(result)).toBe(true);
|
|
160
|
+
|
|
161
|
+
const resultError = Result.unwrapErrThrow(result);
|
|
162
|
+
expect(resultError).toStrictEqual([
|
|
163
|
+
{
|
|
164
|
+
path: ['1'],
|
|
165
|
+
actualValue: '2',
|
|
166
|
+
expectedType: 'number',
|
|
167
|
+
typeName: 'number',
|
|
168
|
+
message: undefined,
|
|
169
|
+
},
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
expect(validationErrorsToMessages(resultError)).toStrictEqual([
|
|
173
|
+
'Expected <number> at 1, got <string> type value "2".',
|
|
174
|
+
]);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('fill', () => {
|
|
179
|
+
test('keeps numeric entries and trims extras', () => {
|
|
180
|
+
const ys: unknown = [4, 5, 6, 7];
|
|
181
|
+
|
|
182
|
+
expect(xs.fill(ys)).toStrictEqual([4, 5, 6]);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('fills missing or invalid entries', () => {
|
|
186
|
+
const ys: unknown = [4, '5'];
|
|
187
|
+
|
|
188
|
+
expect(xs.fill(ys)).toStrictEqual([4, 0, 0]);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('fill with the default value for non-array input', () => {
|
|
192
|
+
const ys: unknown = null;
|
|
193
|
+
|
|
194
|
+
expect(xs.fill(ys)).toStrictEqual([1, 2, 3]);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
});
|
package/src/array/index.mts
CHANGED
|
@@ -342,7 +342,7 @@ describe('literal', () => {
|
|
|
342
342
|
]);
|
|
343
343
|
|
|
344
344
|
expect(validationErrorsToMessages(resultError2)).toStrictEqual([
|
|
345
|
-
'Expected <literal(42n)>, got <bigint> type value `
|
|
345
|
+
'Expected <literal(42n)>, got <bigint> type value `99n`.',
|
|
346
346
|
]);
|
|
347
347
|
});
|
|
348
348
|
|