UNPKG

6.46 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.ObjectPredicate = void 0;
4const is_1 = require("@sindresorhus/is");
5const dotProp = require("dot-prop");
6const isEqual = require("lodash.isequal");
7const has_items_1 = require("../utils/has-items");
8const of_type_1 = require("../utils/of-type");
9const of_type_deep_1 = require("../utils/of-type-deep");
10const match_shape_1 = require("../utils/match-shape");
11const predicate_1 = require("./predicate");
12class ObjectPredicate extends predicate_1.Predicate {
13 /**
14 @hidden
15 */
16 constructor(options) {
17 super('object', options);
18 }
19 /**
20 Test if an Object is a plain object.
21 */
22 get plain() {
23 return this.addValidator({
24 message: (_, label) => `Expected ${label} to be a plain object`,
25 validator: object => is_1.default.plainObject(object)
26 });
27 }
28 /**
29 Test an object to be empty.
30 */
31 get empty() {
32 return this.addValidator({
33 message: (object, label) => `Expected ${label} to be empty, got \`${JSON.stringify(object)}\``,
34 validator: object => Object.keys(object).length === 0
35 });
36 }
37 /**
38 Test an object to be not empty.
39 */
40 get nonEmpty() {
41 return this.addValidator({
42 message: (_, label) => `Expected ${label} to not be empty`,
43 validator: object => Object.keys(object).length > 0
44 });
45 }
46 /**
47 Test all the values in the object to match the provided predicate.
48
49 @param predicate - The predicate that should be applied against every value in the object.
50 */
51 valuesOfType(predicate) {
52 return this.addValidator({
53 message: (_, label, error) => `(${label}) ${error}`,
54 validator: object => of_type_1.default(Object.values(object), predicate)
55 });
56 }
57 /**
58 Test all the values in the object deeply to match the provided predicate.
59
60 @param predicate - The predicate that should be applied against every value in the object.
61 */
62 deepValuesOfType(predicate) {
63 return this.addValidator({
64 message: (_, label, error) => `(${label}) ${error}`,
65 validator: object => of_type_deep_1.default(object, predicate)
66 });
67 }
68 /**
69 Test an object to be deeply equal to the provided object.
70
71 @param expected - Expected object to match.
72 */
73 deepEqual(expected) {
74 return this.addValidator({
75 message: (object, label) => `Expected ${label} to be deeply equal to \`${JSON.stringify(expected)}\`, got \`${JSON.stringify(object)}\``,
76 validator: object => isEqual(object, expected)
77 });
78 }
79 /**
80 Test an object to be of a specific instance type.
81
82 @param instance - The expected instance type of the object.
83 */
84 instanceOf(instance) {
85 return this.addValidator({
86 message: (object, label) => {
87 var _a;
88 let { name } = (_a = object === null || object === void 0 ? void 0 : object.constructor) !== null && _a !== void 0 ? _a : {};
89 if (!name || name === 'Object') {
90 name = JSON.stringify(object);
91 }
92 return `Expected ${label} \`${name}\` to be of type \`${instance.name}\``;
93 },
94 validator: object => object instanceof instance
95 });
96 }
97 /**
98 Test an object to include all the provided keys. You can use [dot-notation](https://github.com/sindresorhus/dot-prop) in a key to access nested properties.
99
100 @param keys - The keys that should be present in the object.
101 */
102 hasKeys(...keys) {
103 return this.addValidator({
104 message: (_, label, missingKeys) => `Expected ${label} to have keys \`${JSON.stringify(missingKeys)}\``,
105 validator: object => has_items_1.default({
106 has: item => dotProp.has(object, item)
107 }, keys)
108 });
109 }
110 /**
111 Test an object to include any of the provided keys. You can use [dot-notation](https://github.com/sindresorhus/dot-prop) in a key to access nested properties.
112
113 @param keys - The keys that could be a key in the object.
114 */
115 hasAnyKeys(...keys) {
116 return this.addValidator({
117 message: (_, label) => `Expected ${label} to have any key of \`${JSON.stringify(keys)}\``,
118 validator: object => keys.some(key => dotProp.has(object, key))
119 });
120 }
121 /**
122 Test an object to match the `shape` partially. This means that it ignores unexpected properties. The shape comparison is deep.
123
124 The shape is an object which describes how the tested object should look like. The keys are the same as the source object and the values are predicates.
125
126 @param shape - Shape to test the object against.
127
128 @example
129 ```
130 import ow from 'ow';
131
132 const object = {
133 unicorn: '🦄',
134 rainbow: '🌈'
135 };
136
137 ow(object, ow.object.partialShape({
138 unicorn: ow.string
139 }));
140 ```
141 */
142 partialShape(shape) {
143 return this.addValidator({
144 // TODO: Improve this when message handling becomes smarter
145 message: (_, label, message) => `${message.replace('Expected', 'Expected property')} in ${label}`,
146 validator: object => match_shape_1.partial(object, shape)
147 });
148 }
149 /**
150 Test an object to match the `shape` exactly. This means that will fail if it comes across unexpected properties. The shape comparison is deep.
151
152 The shape is an object which describes how the tested object should look like. The keys are the same as the source object and the values are predicates.
153
154 @param shape - Shape to test the object against.
155
156 @example
157 ```
158 import ow from 'ow';
159
160 ow({unicorn: '🦄'}, ow.object.exactShape({
161 unicorn: ow.string
162 }));
163 ```
164 */
165 exactShape(shape) {
166 // TODO [typescript@>=5] If higher-kinded types are supported natively by typescript, refactor `addValidator` to use them to avoid the usage of `any`. Otherwise, bump or remove this TODO.
167 return this.addValidator({
168 // TODO: Improve this when message handling becomes smarter
169 message: (_, label, message) => `${message.replace('Expected', 'Expected property')} in ${label}`,
170 validator: object => match_shape_1.exact(object, shape)
171 });
172 }
173}
174exports.ObjectPredicate = ObjectPredicate;