1 | import { deepEqual } from 'fast-equals';
|
2 | import { exact } from '../utils/match-shape.js';
|
3 | import ofType from '../utils/of-type.js';
|
4 | import { Predicate } from './predicate.js';
|
5 | export class ArrayPredicate extends Predicate {
|
6 | |
7 |
|
8 |
|
9 | constructor(options) {
|
10 | super('array', options);
|
11 | }
|
12 | |
13 |
|
14 |
|
15 |
|
16 |
|
17 | length(length) {
|
18 | return this.addValidator({
|
19 | message: (value, label) => `Expected ${label} to have length \`${length}\`, got \`${value.length}\``,
|
20 | validator: value => value.length === length,
|
21 | });
|
22 | }
|
23 | |
24 |
|
25 |
|
26 |
|
27 |
|
28 | minLength(length) {
|
29 | return this.addValidator({
|
30 | message: (value, label) => `Expected ${label} to have a minimum length of \`${length}\`, got \`${value.length}\``,
|
31 | validator: value => value.length >= length,
|
32 | negatedMessage: (value, label) => `Expected ${label} to have a maximum length of \`${length - 1}\`, got \`${value.length}\``,
|
33 | });
|
34 | }
|
35 | |
36 |
|
37 |
|
38 |
|
39 |
|
40 | maxLength(length) {
|
41 | return this.addValidator({
|
42 | message: (value, label) => `Expected ${label} to have a maximum length of \`${length}\`, got \`${value.length}\``,
|
43 | validator: value => value.length <= length,
|
44 | negatedMessage: (value, label) => `Expected ${label} to have a minimum length of \`${length + 1}\`, got \`${value.length}\``,
|
45 | });
|
46 | }
|
47 | |
48 |
|
49 |
|
50 |
|
51 |
|
52 | startsWith(searchElement) {
|
53 | return this.addValidator({
|
54 | message: (value, label) => `Expected ${label} to start with \`${searchElement}\`, got \`${value[0]}\``,
|
55 | validator: value => value[0] === searchElement,
|
56 | });
|
57 | }
|
58 | |
59 |
|
60 |
|
61 |
|
62 |
|
63 | endsWith(searchElement) {
|
64 | return this.addValidator({
|
65 | message: (value, label) => `Expected ${label} to end with \`${searchElement}\`, got \`${value.at(-1)}\``,
|
66 | validator: value => value.at(-1) === searchElement,
|
67 | });
|
68 | }
|
69 | |
70 |
|
71 |
|
72 |
|
73 |
|
74 | includes(...searchElements) {
|
75 | return this.addValidator({
|
76 | message: (value, label) => `Expected ${label} to include all elements of \`${JSON.stringify(searchElements)}\`, got \`${JSON.stringify(value)}\``,
|
77 | validator: value => searchElements.every(element => value.includes(element)),
|
78 | });
|
79 | }
|
80 | |
81 |
|
82 |
|
83 |
|
84 |
|
85 | includesAny(...searchElements) {
|
86 | return this.addValidator({
|
87 | message: (value, label) => `Expected ${label} to include any element of \`${JSON.stringify(searchElements)}\`, got \`${JSON.stringify(value)}\``,
|
88 | validator: value => searchElements.some(element => value.includes(element)),
|
89 | });
|
90 | }
|
91 | |
92 |
|
93 |
|
94 | get empty() {
|
95 | return this.addValidator({
|
96 | message: (value, label) => `Expected ${label} to be empty, got \`${JSON.stringify(value)}\``,
|
97 | validator: value => value.length === 0,
|
98 | });
|
99 | }
|
100 | |
101 |
|
102 |
|
103 | get nonEmpty() {
|
104 | return this.addValidator({
|
105 | message: (_, label) => `Expected ${label} to not be empty`,
|
106 | validator: value => value.length > 0,
|
107 | });
|
108 | }
|
109 | |
110 |
|
111 |
|
112 |
|
113 |
|
114 | deepEqual(expected) {
|
115 | return this.addValidator({
|
116 | message: (value, label) => `Expected ${label} to be deeply equal to \`${JSON.stringify(expected)}\`, got \`${JSON.stringify(value)}\``,
|
117 | validator: value => deepEqual(value, expected),
|
118 | });
|
119 | }
|
120 | |
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | ofType(predicate) {
|
131 |
|
132 | return this.addValidator({
|
133 | message: (_, label, error) => `(${label}) ${error}`,
|
134 | validator: value => ofType(value, 'values', predicate),
|
135 | });
|
136 | }
|
137 | |
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 | exactShape(predicates) {
|
148 | const shape = predicates;
|
149 | return this.addValidator({
|
150 |
|
151 | message: (_, label, message) => `${message.replace('Expected', 'Expected element')} in ${label}`,
|
152 | validator: object => exact(object, shape, undefined, true),
|
153 | });
|
154 | }
|
155 | }
|