deep-guards 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
- package/.yarn/plugins/@yarnpkg/plugin-version.cjs +523 -0
- package/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs +28 -0
- package/.yarn/releases/yarn-3.8.2.cjs +875 -0
- package/.yarn.yml +11 -0
- package/LICENSE +201 -0
- package/README.md +167 -0
- package/babel.config.cjs +6 -0
- package/dist/compound.d.ts +8 -0
- package/dist/compound.js +48 -0
- package/dist/compound.js.map +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/primitives.d.ts +10 -0
- package/dist/primitives.js +10 -0
- package/dist/primitives.js.map +1 -0
- package/dist/structures.d.ts +9 -0
- package/dist/structures.js +41 -0
- package/dist/structures.js.map +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/eslint.config.js +51 -0
- package/package.json +41 -0
- package/src/compound.ts +81 -0
- package/src/errors.ts +17 -0
- package/src/index.ts +5 -0
- package/src/primitives.ts +23 -0
- package/src/structures.ts +83 -0
- package/src/types.ts +5 -0
- package/tests/compound.test.ts +136 -0
- package/tests/primitives.test.ts +91 -0
- package/tests/structures.test.ts +110 -0
- package/tsconfig.json +25 -0
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "eniallator",
|
|
3
|
+
"description": "Deep guarding package",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"name": "deep-guards",
|
|
7
|
+
"packageManager": "yarn@3.8.2",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"version": "1.0.0",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"lint": "eslint ./src",
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"findissues": "yarn typecheck && yarn lint"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@babel/core": "^7.26.0",
|
|
20
|
+
"@babel/preset-env": "^7.26.0",
|
|
21
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
22
|
+
"@eslint/compat": "^1.2.3",
|
|
23
|
+
"@eslint/js": "^9.15.0",
|
|
24
|
+
"@jest/globals": "^29.7.0",
|
|
25
|
+
"@types/babel__core": "^7.20.5",
|
|
26
|
+
"@types/babel__preset-env": "^7.9.7",
|
|
27
|
+
"@types/eslint": "^9.6.1",
|
|
28
|
+
"@types/eslint__js": "^8.42.3",
|
|
29
|
+
"@types/jest": "^29.5.14",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^8.15.0",
|
|
31
|
+
"@typescript-eslint/parser": "^8.15.0",
|
|
32
|
+
"babel-jest": "^29.7.0",
|
|
33
|
+
"eslint": "^9.15.0",
|
|
34
|
+
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
35
|
+
"eslint-plugin-import": "^2.31.0",
|
|
36
|
+
"eslint-plugin-jest": "^28.9.0",
|
|
37
|
+
"jest": "^29.7.0",
|
|
38
|
+
"typescript": "^5.6.3",
|
|
39
|
+
"typescript-eslint": "^8.15.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/src/compound.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Guard, GuardSchemaOf } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export function isOptional<T>(guard: Guard<T>): Guard<T | undefined> {
|
|
4
|
+
if (typeof guard !== "function") {
|
|
5
|
+
throw new TypeError(
|
|
6
|
+
`isOptional expects a guard parameter. Got instead: ${guard}`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return ((value) => value === undefined || guard(value)) as Guard<
|
|
11
|
+
T | undefined
|
|
12
|
+
>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isNullable<T>(guard: Guard<T>): Guard<T | null | undefined> {
|
|
16
|
+
if (typeof guard !== "function") {
|
|
17
|
+
throw new TypeError(
|
|
18
|
+
`isNullable expects a guard parameter. Got instead: ${guard}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (value: unknown): value is T | null | undefined =>
|
|
23
|
+
value == null || guard(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isNonNullable<T>(value: T | null | undefined): value is T {
|
|
27
|
+
return value != null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function isNot<const N>(guard: Guard<N>) {
|
|
31
|
+
if (typeof guard !== "function") {
|
|
32
|
+
throw new TypeError(
|
|
33
|
+
`isNot expects a guard parameter. Got instead: ${guard}`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return <const T>(value: T | N): value is T => !guard(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function isOneOf<
|
|
41
|
+
const T extends (string | number | boolean | symbol | null | undefined)[]
|
|
42
|
+
>(...values: T): Guard<(typeof values)[number]> {
|
|
43
|
+
const valueSet = new Set(values);
|
|
44
|
+
return (value: unknown): value is T[number] =>
|
|
45
|
+
valueSet.has(value as T[number]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isUnionOf<T extends readonly unknown[]>(
|
|
49
|
+
...guards: GuardSchemaOf<T>
|
|
50
|
+
): Guard<T[number]> {
|
|
51
|
+
if (guards.every((guard) => typeof guard !== "function")) {
|
|
52
|
+
throw new TypeError(
|
|
53
|
+
`isUnionOf expects N guard parameters. Got instead: ${guards}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (value): value is T => guards.some((guard) => guard(value));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isEqual<T>(a: T, b: unknown): b is T {
|
|
61
|
+
return (
|
|
62
|
+
a === b ||
|
|
63
|
+
(a != null &&
|
|
64
|
+
b != null &&
|
|
65
|
+
typeof a === "object" &&
|
|
66
|
+
typeof b === "object" &&
|
|
67
|
+
(Array.isArray(a)
|
|
68
|
+
? Array.isArray(b) &&
|
|
69
|
+
a.length === b.length &&
|
|
70
|
+
a.every((v, i) => isEqual(v, b[i]))
|
|
71
|
+
: Object.keys(a).length === Object.keys(b).length &&
|
|
72
|
+
Object.entries(a).every(
|
|
73
|
+
([k, v]) => k in b && isEqual(v, (b as Record<string, unknown>)[k])
|
|
74
|
+
)))
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isExact<const T>(expected: T, deep: boolean = true): Guard<T> {
|
|
79
|
+
return (value): value is T =>
|
|
80
|
+
deep ? isEqual(expected, value) : expected === value;
|
|
81
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Guard } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export class GuardError extends Error {
|
|
4
|
+
name = "GuardError";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function guardOrThrow<T>(
|
|
8
|
+
value: unknown,
|
|
9
|
+
guard: Guard<T>,
|
|
10
|
+
hint?: string
|
|
11
|
+
): T {
|
|
12
|
+
if (guard(value)) {
|
|
13
|
+
return value;
|
|
14
|
+
} else {
|
|
15
|
+
throw new GuardError(hint ?? "Guard error");
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Guard } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export const isUnknown: Guard<unknown> = (_value): _value is unknown => true;
|
|
4
|
+
|
|
5
|
+
export const isNull: Guard<null> = (value) => value === null;
|
|
6
|
+
|
|
7
|
+
export const isUndefined: Guard<undefined> = (value) => value === undefined;
|
|
8
|
+
|
|
9
|
+
export const isNumber: Guard<number> = (value) => typeof value === "number";
|
|
10
|
+
|
|
11
|
+
export const isInteger: Guard<number> = (value): value is number =>
|
|
12
|
+
Number.isInteger(value);
|
|
13
|
+
|
|
14
|
+
export const isString: Guard<string> = (value) => typeof value === "string";
|
|
15
|
+
|
|
16
|
+
export const isSymbol: Guard<symbol> = (value) => typeof value === "symbol";
|
|
17
|
+
|
|
18
|
+
export const isBoolean: Guard<boolean> = (value) =>
|
|
19
|
+
value === true || value === false;
|
|
20
|
+
|
|
21
|
+
export const isFunction: Guard<(...args: unknown[]) => unknown> = (
|
|
22
|
+
value
|
|
23
|
+
): value is (...args: unknown[]) => unknown => typeof value === "function";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Guard, GuardSchemaOf } from "./types.js";
|
|
2
|
+
|
|
3
|
+
type ObjectKey = string | number | symbol;
|
|
4
|
+
|
|
5
|
+
function objectKeys<K extends ObjectKey>(obj: Record<K, unknown>): K[] {
|
|
6
|
+
return (Object.getOwnPropertyNames(obj) as K[]).concat(
|
|
7
|
+
Object.getOwnPropertySymbols(obj) as K[]
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const isAnyArray: Guard<unknown[]> = (value) => Array.isArray(value);
|
|
12
|
+
|
|
13
|
+
export const isAnyRecord: Guard<Record<ObjectKey, unknown>> = (
|
|
14
|
+
value
|
|
15
|
+
): value is Record<ObjectKey, unknown> =>
|
|
16
|
+
value != null && typeof value === "object" && !Array.isArray(value);
|
|
17
|
+
|
|
18
|
+
export function isArrayOf<T>(guard: Guard<T>): Guard<T[]> {
|
|
19
|
+
if (typeof guard !== "function") {
|
|
20
|
+
throw new TypeError(
|
|
21
|
+
`isArrayOf expects a guard parameter. Got instead: ${guard}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (value): value is T[] => Array.isArray(value) && value.every(guard);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isRecordOf<K extends ObjectKey>(
|
|
29
|
+
keyGuard: Guard<K>
|
|
30
|
+
): Guard<Record<K, unknown>>;
|
|
31
|
+
export function isRecordOf<K extends ObjectKey, V>(
|
|
32
|
+
keyGuard: Guard<K>,
|
|
33
|
+
valueGuard: Guard<V>
|
|
34
|
+
): Guard<Record<K, V>>;
|
|
35
|
+
export function isRecordOf<K extends ObjectKey, V>(
|
|
36
|
+
keyGuard: Guard<K>,
|
|
37
|
+
valueGuard?: Guard<V>
|
|
38
|
+
): Guard<Record<K, V>> {
|
|
39
|
+
if (typeof keyGuard !== "function") {
|
|
40
|
+
throw new TypeError(
|
|
41
|
+
`isRecordOf keyGuard expects a guard parameter. Got instead: ${keyGuard}`
|
|
42
|
+
);
|
|
43
|
+
} else if (valueGuard != null && typeof valueGuard !== "function") {
|
|
44
|
+
throw new TypeError(
|
|
45
|
+
`isRecordOf valueGuard expects an optional guard parameter. Got instead: ${valueGuard}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (value): value is Record<K, V> =>
|
|
50
|
+
value != null &&
|
|
51
|
+
typeof value === "object" &&
|
|
52
|
+
!Array.isArray(value) &&
|
|
53
|
+
objectKeys(value).every(
|
|
54
|
+
(key) => keyGuard(key) && (valueGuard?.(value[key]) ?? true)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function isObjectOf<O extends object>(
|
|
59
|
+
schema: GuardSchemaOf<O>
|
|
60
|
+
): O extends unknown[] ? never : Guard<O> {
|
|
61
|
+
const schemaKeys = objectKeys(schema);
|
|
62
|
+
const schemaUnknown = schema as unknown;
|
|
63
|
+
if (schemaKeys.length === 0) {
|
|
64
|
+
throw new Error("isObjectOf received an empty schema");
|
|
65
|
+
} else if (
|
|
66
|
+
schemaUnknown == null ||
|
|
67
|
+
typeof schemaUnknown !== "object" ||
|
|
68
|
+
Array.isArray(schemaUnknown) ||
|
|
69
|
+
schemaKeys.some((key) => typeof (schemaUnknown as O)[key] !== "function")
|
|
70
|
+
) {
|
|
71
|
+
throw new TypeError(
|
|
72
|
+
`isObjectOf expects a guard schema. Got instead: ${schemaUnknown}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return ((value): value is O =>
|
|
77
|
+
value != null &&
|
|
78
|
+
typeof value === "object" &&
|
|
79
|
+
!Array.isArray(value) &&
|
|
80
|
+
schemaKeys.every(
|
|
81
|
+
(key) => key in value && schema[key]((value as O)[key])
|
|
82
|
+
)) as O extends unknown[] ? never : Guard<O>;
|
|
83
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isExact,
|
|
3
|
+
isNot,
|
|
4
|
+
isNullable,
|
|
5
|
+
isNonNullable,
|
|
6
|
+
isOneOf,
|
|
7
|
+
isOptional,
|
|
8
|
+
isUnionOf,
|
|
9
|
+
} from "../src/compound";
|
|
10
|
+
import { isNumber, isString } from "../src/primitives";
|
|
11
|
+
|
|
12
|
+
describe("isOptional", () => {
|
|
13
|
+
const guard = isOptional(isString);
|
|
14
|
+
|
|
15
|
+
it("succeeds for the expected type or undefined", () => {
|
|
16
|
+
expect(guard("foo")).toBe(true);
|
|
17
|
+
expect(guard(undefined)).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("fails for any other value", () => {
|
|
21
|
+
expect(guard(null)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe("isNullable", () => {
|
|
26
|
+
const guard = isNullable(isString);
|
|
27
|
+
|
|
28
|
+
it("succeeds for the expected type, null, or undefined", () => {
|
|
29
|
+
expect(guard("foo")).toBe(true);
|
|
30
|
+
expect(guard(null)).toBe(true);
|
|
31
|
+
expect(guard(undefined)).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("fails any other value", () => {
|
|
35
|
+
expect(guard(1)).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("isNonNullable", () => {
|
|
40
|
+
const guard = isNonNullable;
|
|
41
|
+
|
|
42
|
+
it("succeeds for the expected type, null, or undefined", () => {
|
|
43
|
+
expect(guard("foo")).toBe(true);
|
|
44
|
+
expect(guard(1)).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("fails any other value", () => {
|
|
48
|
+
expect(guard(null)).toBe(false);
|
|
49
|
+
expect(guard(undefined)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("isNot", () => {
|
|
54
|
+
const guard = isNot(isString);
|
|
55
|
+
|
|
56
|
+
it("succeeds for any other value", () => {
|
|
57
|
+
expect(guard(1)).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("fails for the isNot type", () => {
|
|
61
|
+
expect(guard("foo")).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("isOneOf", () => {
|
|
66
|
+
const guard = isOneOf(1, "foo", true);
|
|
67
|
+
|
|
68
|
+
it("succeeds for all of the values", () => {
|
|
69
|
+
expect(guard(1)).toBe(true);
|
|
70
|
+
expect(guard("foo")).toBe(true);
|
|
71
|
+
expect(guard(true)).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(guard(2)).toBe(false);
|
|
75
|
+
it("fails any other value", () => {
|
|
76
|
+
expect(guard(null)).toBe(false);
|
|
77
|
+
expect(guard("bar")).toBe(false);
|
|
78
|
+
expect(guard(false)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("isUnionOf", () => {
|
|
83
|
+
const guard = isUnionOf(isString, isNumber);
|
|
84
|
+
it("succeeds for the union types", () => {
|
|
85
|
+
expect(guard(1)).toBe(true);
|
|
86
|
+
expect(guard("foo")).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("fails for any other type", () => {
|
|
90
|
+
expect(guard(true)).toBe(false);
|
|
91
|
+
expect(guard(null)).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("isExact", () => {
|
|
96
|
+
describe("deep", () => {
|
|
97
|
+
const guard = isExact(
|
|
98
|
+
{ foo: "bar", hello: ["world", { key: "test" }] },
|
|
99
|
+
true
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
it("succeeds for the exact value", () => {
|
|
103
|
+
expect(guard({ foo: "bar", hello: ["world", { key: "test" }] })).toBe(
|
|
104
|
+
true
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("fails for any other value", () => {
|
|
109
|
+
expect(guard({ foo: "baz", hello: ["world", { key: "test" }] })).toBe(
|
|
110
|
+
false
|
|
111
|
+
);
|
|
112
|
+
expect(guard({ foo: "bar", hello: ["world", { key: "tester" }] })).toBe(
|
|
113
|
+
false
|
|
114
|
+
);
|
|
115
|
+
expect(guard(1)).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("shallow", () => {
|
|
120
|
+
const guard = isExact("foo", false);
|
|
121
|
+
|
|
122
|
+
it("succeeds for the exact value", () => {
|
|
123
|
+
expect(guard("foo")).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("fails for deep equality", () => {
|
|
127
|
+
const guard = isExact(["foo", "bar", "baz", 1, 2, 3], false);
|
|
128
|
+
expect(guard(["foo", "bar", "baz", 1, 2, 3])).toBe(false);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("fails for any other value", () => {
|
|
132
|
+
expect(guard("bar")).toBe(false);
|
|
133
|
+
expect(guard(1)).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isBoolean,
|
|
3
|
+
isFunction,
|
|
4
|
+
isInteger,
|
|
5
|
+
isNull,
|
|
6
|
+
isNumber,
|
|
7
|
+
isString,
|
|
8
|
+
isUndefined,
|
|
9
|
+
isUnknown,
|
|
10
|
+
} from "../src/primitives";
|
|
11
|
+
|
|
12
|
+
describe("isUnknown", () => {
|
|
13
|
+
it("succeeds for any value", () => {
|
|
14
|
+
expect(isUnknown("unknown")).toBe(true);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("isAnyFunction", () => {
|
|
19
|
+
it("succeeds for a function", () => {
|
|
20
|
+
expect(isFunction(() => {})).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("fails for any other value", () => {
|
|
24
|
+
expect(isFunction(1)).toBe(false);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("isNull", () => {
|
|
29
|
+
it("succeeds for null", () => {
|
|
30
|
+
expect(isNull(null)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("fails for any other value", () => {
|
|
34
|
+
expect(isNull(undefined)).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("isUndefined", () => {
|
|
39
|
+
it("succeeds for undefined", () => {
|
|
40
|
+
expect(isUndefined(undefined)).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("fails for any other value", () => {
|
|
44
|
+
expect(isUndefined(null)).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("isNumber", () => {
|
|
49
|
+
it("succeeds for a number", () => {
|
|
50
|
+
expect(isNumber(1.23)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("fails for any other type", () => {
|
|
54
|
+
expect(isNumber("foo")).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("isInteger", () => {
|
|
59
|
+
it("succeeds for an integer", () => {
|
|
60
|
+
expect(isInteger(1)).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("fails for a non-integer", () => {
|
|
64
|
+
expect(isInteger(1.23)).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("fails for any other type", () => {
|
|
68
|
+
expect(isInteger("foo")).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("isString", () => {
|
|
73
|
+
it("succeeds for a string", () => {
|
|
74
|
+
expect(isString("Foo bar")).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("fails for other types", () => {
|
|
78
|
+
expect(isString(true)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("isBoolean", () => {
|
|
83
|
+
it("succeeds for a boolean", () => {
|
|
84
|
+
expect(isBoolean(true)).toBe(true);
|
|
85
|
+
expect(isBoolean(false)).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("fails for other types", () => {
|
|
89
|
+
expect(isBoolean("foo")).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { isNumber, isString, isSymbol } from "../src/primitives";
|
|
2
|
+
import {
|
|
3
|
+
isAnyArray,
|
|
4
|
+
isAnyRecord,
|
|
5
|
+
isArrayOf,
|
|
6
|
+
isObjectOf,
|
|
7
|
+
isRecordOf,
|
|
8
|
+
} from "../src/structures";
|
|
9
|
+
|
|
10
|
+
describe("isAnyArray", () => {
|
|
11
|
+
it("succeeds for an array", () => {
|
|
12
|
+
expect(isAnyArray([])).toBe(true);
|
|
13
|
+
expect(isAnyArray(["foo", 1, true, null])).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("fails for any other value", () => {
|
|
17
|
+
expect(isAnyArray({})).toBe(false);
|
|
18
|
+
expect(isAnyArray(1)).toBe(false);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe("isAnyRecord", () => {
|
|
23
|
+
it("succeeds for a record", () => {
|
|
24
|
+
expect(isAnyRecord({})).toBe(true);
|
|
25
|
+
expect(isAnyRecord({ foo: "bar", baz: 1 })).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("fails for any other value", () => {
|
|
29
|
+
expect(isAnyRecord([])).toBe(false);
|
|
30
|
+
expect(isAnyRecord(1)).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("isArrayOf", () => {
|
|
35
|
+
const guard = isArrayOf(isString);
|
|
36
|
+
|
|
37
|
+
it("succeeds for an array of the value", () => {
|
|
38
|
+
expect(guard([])).toBe(true);
|
|
39
|
+
expect(guard(["foo", "bar", "baz"])).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("fails for any other value", () => {
|
|
43
|
+
expect(guard([1, 2, 3])).toBe(false);
|
|
44
|
+
expect(guard(["foo", "bar", null])).toBe(false);
|
|
45
|
+
expect(guard(1)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("isObjectOf", () => {
|
|
50
|
+
const barSymbol = Symbol("bar");
|
|
51
|
+
const guard = isObjectOf({
|
|
52
|
+
foo: isString,
|
|
53
|
+
[barSymbol]: isNumber,
|
|
54
|
+
baz: isObjectOf({
|
|
55
|
+
qux: isSymbol,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("succeeds for an object of the value", () => {
|
|
60
|
+
expect(
|
|
61
|
+
guard({
|
|
62
|
+
foo: "hello",
|
|
63
|
+
[barSymbol]: 1,
|
|
64
|
+
baz: { qux: Symbol("world!") },
|
|
65
|
+
quux: "this should not be checked",
|
|
66
|
+
})
|
|
67
|
+
).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("fails for any other value", () => {
|
|
71
|
+
expect(
|
|
72
|
+
guard({
|
|
73
|
+
foo: "hello",
|
|
74
|
+
[barSymbol]: "FAIL",
|
|
75
|
+
baz: { qux: Symbol("world!") },
|
|
76
|
+
})
|
|
77
|
+
).toBe(false);
|
|
78
|
+
expect(guard(1)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("isRecordOf", () => {
|
|
83
|
+
describe("with valueGuard", () => {
|
|
84
|
+
const guard = isRecordOf(isString, isNumber);
|
|
85
|
+
|
|
86
|
+
it("succeeds for a record of the key/value types", () => {
|
|
87
|
+
expect(guard({})).toBe(true);
|
|
88
|
+
expect(guard({ foo: 1, bar: 2 })).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("fails for any other value", () => {
|
|
92
|
+
expect(guard({ foo: "bar", baz: 1 })).toBe(false);
|
|
93
|
+
expect(guard(1)).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe("without valueGuard", () => {
|
|
98
|
+
const guard = isRecordOf(isString);
|
|
99
|
+
|
|
100
|
+
it("succeeds for a record with the key type", () => {
|
|
101
|
+
expect(guard({})).toBe(true);
|
|
102
|
+
expect(guard({ foo: 1, bar: "baz" })).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("fails for any other value", () => {
|
|
106
|
+
expect(guard({ 1: "foo", [Symbol("bar")]: 1 })).toBe(false);
|
|
107
|
+
expect(guard(1)).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["src"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"allowJs": false,
|
|
5
|
+
"allowSyntheticDefaultImports": true,
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"downlevelIteration": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"lib": ["esnext"],
|
|
12
|
+
"module": "esnext",
|
|
13
|
+
"sourceRoot": "src",
|
|
14
|
+
"moduleResolution": "Bundler",
|
|
15
|
+
"noErrorTruncation": true,
|
|
16
|
+
"noFallthroughCasesInSwitch": true,
|
|
17
|
+
"noUncheckedIndexedAccess": true,
|
|
18
|
+
"outDir": "dist",
|
|
19
|
+
"resolveJsonModule": true,
|
|
20
|
+
"skipLibCheck": true,
|
|
21
|
+
"sourceMap": true,
|
|
22
|
+
"strict": true,
|
|
23
|
+
"target": "esnext"
|
|
24
|
+
}
|
|
25
|
+
}
|