UNPKG

7.54 kBJavaScriptView Raw
1import is from '@sindresorhus/is';
2import { Predicate } from './predicate.js';
3export class StringPredicate extends Predicate {
4 /**
5 @hidden
6 */
7 constructor(options) {
8 super('string', options);
9 }
10 /**
11 Test a string to have a specific length.
12
13 @param length - The length of the string.
14 */
15 length(length) {
16 return this.addValidator({
17 message: (value, label) => `Expected ${label} to have length \`${length}\`, got \`${value}\``,
18 validator: value => value.length === length,
19 });
20 }
21 /**
22 Test a string to have a minimum length.
23
24 @param length - The minimum length of the string.
25 */
26 minLength(length) {
27 return this.addValidator({
28 message: (value, label) => `Expected ${label} to have a minimum length of \`${length}\`, got \`${value}\``,
29 validator: value => value.length >= length,
30 negatedMessage: (value, label) => `Expected ${label} to have a maximum length of \`${length - 1}\`, got \`${value}\``,
31 });
32 }
33 /**
34 Test a string to have a maximum length.
35
36 @param length - The maximum length of the string.
37 */
38 maxLength(length) {
39 return this.addValidator({
40 message: (value, label) => `Expected ${label} to have a maximum length of \`${length}\`, got \`${value}\``,
41 validator: value => value.length <= length,
42 negatedMessage: (value, label) => `Expected ${label} to have a minimum length of \`${length + 1}\`, got \`${value}\``,
43 });
44 }
45 /**
46 Test a string against a regular expression.
47
48 @param regex - The regular expression to match the value with.
49 */
50 matches(regex) {
51 return this.addValidator({
52 message: (value, label) => `Expected ${label} to match \`${regex}\`, got \`${value}\``,
53 validator: value => regex.test(value),
54 });
55 }
56 /**
57 Test a string to start with a specific value.
58
59 @param searchString - The value that should be the start of the string.
60 */
61 startsWith(searchString) {
62 return this.addValidator({
63 message: (value, label) => `Expected ${label} to start with \`${searchString}\`, got \`${value}\``,
64 validator: value => value.startsWith(searchString),
65 });
66 }
67 /**
68 Test a string to end with a specific value.
69
70 @param searchString - The value that should be the end of the string.
71 */
72 endsWith(searchString) {
73 return this.addValidator({
74 message: (value, label) => `Expected ${label} to end with \`${searchString}\`, got \`${value}\``,
75 validator: value => value.endsWith(searchString),
76 });
77 }
78 /**
79 Test a string to include a specific value.
80
81 @param searchString - The value that should be included in the string.
82 */
83 includes(searchString) {
84 return this.addValidator({
85 message: (value, label) => `Expected ${label} to include \`${searchString}\`, got \`${value}\``,
86 validator: value => value.includes(searchString),
87 });
88 }
89 /**
90 Test if the string is an element of the provided list.
91
92 @param list - List of possible values.
93 */
94 oneOf(list) {
95 return this.addValidator({
96 message(value, label) {
97 let printedList = JSON.stringify(list);
98 if (list.length > 10) {
99 const overflow = list.length - 10;
100 printedList = JSON.stringify(list.slice(0, 10)).replace(/]$/, `,…+${overflow} more]`);
101 }
102 return `Expected ${label} to be one of \`${printedList}\`, got \`${value}\``;
103 },
104 validator: value => list.includes(value),
105 });
106 }
107 /**
108 Test a string to be empty.
109 */
110 get empty() {
111 return this.addValidator({
112 message: (value, label) => `Expected ${label} to be empty, got \`${value}\``,
113 validator: value => value === '',
114 });
115 }
116 /**
117 Test a string to contain at least 1 non-whitespace character.
118 */
119 get nonBlank() {
120 return this.addValidator({
121 message(value, label) {
122 // Unicode's formal substitute characters can be barely legible and may not be easily recognized.
123 // Hence this alternative substitution scheme.
124 const madeVisible = value
125 .replaceAll(' ', '·')
126 .replaceAll('\f', '\\f')
127 .replaceAll('\n', '\\n')
128 .replaceAll('\r', '\\r')
129 .replaceAll('\t', '\\t')
130 .replaceAll('\v', '\\v');
131 return `Expected ${label} to not be only whitespace, got \`${madeVisible}\``;
132 },
133 validator: value => value.trim() !== '',
134 });
135 }
136 /**
137 Test a string to be not empty.
138 */
139 get nonEmpty() {
140 return this.addValidator({
141 message: (_, label) => `Expected ${label} to not be empty`,
142 validator: value => value !== '',
143 });
144 }
145 /**
146 Test a string to be equal to a specified string.
147
148 @param expected - Expected value to match.
149 */
150 equals(expected) {
151 return this.addValidator({
152 message: (value, label) => `Expected ${label} to be equal to \`${expected}\`, got \`${value}\``,
153 validator: value => value === expected,
154 });
155 }
156 /**
157 Test a string to be alphanumeric.
158 */
159 get alphanumeric() {
160 return this.addValidator({
161 message: (value, label) => `Expected ${label} to be alphanumeric, got \`${value}\``,
162 validator: value => /^[a-z\d]+$/i.test(value),
163 });
164 }
165 /**
166 Test a string to be alphabetical.
167 */
168 get alphabetical() {
169 return this.addValidator({
170 message: (value, label) => `Expected ${label} to be alphabetical, got \`${value}\``,
171 validator: value => /^[a-z]+$/gi.test(value),
172 });
173 }
174 /**
175 Test a string to be numeric.
176 */
177 get numeric() {
178 return this.addValidator({
179 message: (value, label) => `Expected ${label} to be numeric, got \`${value}\``,
180 validator: value => /^[+-]?\d+$/i.test(value),
181 });
182 }
183 /**
184 Test a string to be a valid date.
185 */
186 get date() {
187 return this.addValidator({
188 message: (value, label) => `Expected ${label} to be a date, got \`${value}\``,
189 validator: value => is.validDate(new Date(value)),
190 });
191 }
192 /**
193 Test a non-empty string to be lowercase. Matching both alphabetical & numbers.
194 */
195 get lowercase() {
196 return this.addValidator({
197 message: (value, label) => `Expected ${label} to be lowercase, got \`${value}\``,
198 validator: value => value.trim() !== '' && value === value.toLowerCase(),
199 });
200 }
201 /**
202 Test a non-empty string to be uppercase. Matching both alphabetical & numbers.
203 */
204 get uppercase() {
205 return this.addValidator({
206 message: (value, label) => `Expected ${label} to be uppercase, got \`${value}\``,
207 validator: value => value.trim() !== '' && value === value.toUpperCase(),
208 });
209 }
210 /**
211 Test a string to be a valid URL.
212 */
213 get url() {
214 return this.addValidator({
215 message: (value, label) => `Expected ${label} to be a URL, got \`${value}\``,
216 validator: is.urlString,
217 });
218 }
219}