vest 4.4.0 → 4.4.2-dev-d13b14

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.
Files changed (49) hide show
  1. package/dist/cjs/classnames.development.js +9 -60
  2. package/dist/cjs/classnames.production.js +1 -1
  3. package/dist/cjs/enforce/compose.development.js +6 -53
  4. package/dist/cjs/enforce/compose.production.js +1 -1
  5. package/dist/cjs/enforce/compounds.development.js +16 -71
  6. package/dist/cjs/enforce/compounds.production.js +1 -1
  7. package/dist/cjs/enforce/schema.development.js +6 -58
  8. package/dist/cjs/enforce/schema.production.js +1 -1
  9. package/dist/cjs/parser.development.js +8 -59
  10. package/dist/cjs/parser.production.js +1 -1
  11. package/dist/cjs/promisify.development.js +2 -26
  12. package/dist/cjs/promisify.production.js +1 -1
  13. package/dist/cjs/vest.development.js +163 -429
  14. package/dist/cjs/vest.production.js +1 -1
  15. package/dist/es/classnames.development.js +1 -52
  16. package/dist/es/classnames.production.js +1 -1
  17. package/dist/es/enforce/compose.development.js +4 -51
  18. package/dist/es/enforce/compose.production.js +1 -1
  19. package/dist/es/enforce/compounds.development.js +11 -66
  20. package/dist/es/enforce/compounds.production.js +1 -1
  21. package/dist/es/enforce/schema.development.js +2 -54
  22. package/dist/es/enforce/schema.production.js +1 -1
  23. package/dist/es/parser.development.js +1 -52
  24. package/dist/es/parser.production.js +1 -1
  25. package/dist/es/promisify.development.js +1 -25
  26. package/dist/es/promisify.production.js +1 -1
  27. package/dist/es/vest.development.js +92 -358
  28. package/dist/es/vest.production.js +1 -1
  29. package/dist/umd/classnames.development.js +13 -13
  30. package/dist/umd/classnames.production.js +1 -1
  31. package/dist/umd/enforce/compose.development.js +121 -121
  32. package/dist/umd/enforce/compose.production.js +1 -1
  33. package/dist/umd/enforce/compounds.development.js +180 -184
  34. package/dist/umd/enforce/compounds.production.js +1 -1
  35. package/dist/umd/enforce/schema.development.js +132 -132
  36. package/dist/umd/enforce/schema.production.js +1 -1
  37. package/dist/umd/parser.development.js +13 -13
  38. package/dist/umd/parser.production.js +1 -1
  39. package/dist/umd/vest.development.js +399 -406
  40. package/dist/umd/vest.production.js +1 -1
  41. package/package.json +4 -3
  42. package/testUtils/mockThrowError.ts +2 -1
  43. package/testUtils/suiteDummy.ts +1 -1
  44. package/testUtils/testObjects.ts +2 -17
  45. package/types/enforce/compose.d.ts +14 -30
  46. package/types/enforce/compounds.d.ts +14 -30
  47. package/types/enforce/schema.d.ts +14 -30
  48. package/types/vest.d.ts +4 -3
  49. package/testUtils/itWithContext.ts +0 -23
@@ -4,12 +4,6 @@
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.vest = {}));
5
5
  }(this, (function (exports) { 'use strict';
6
6
 
7
- var assign = Object.assign;
8
-
9
- function isFunction(value) {
10
- return typeof value === 'function';
11
- }
12
-
13
7
  function bindNot(fn) {
14
8
  return function () {
15
9
  var args = [];
@@ -20,6 +14,69 @@
20
14
  };
21
15
  }
22
16
 
17
+ function isNumeric(value) {
18
+ var str = String(value);
19
+ var num = Number(value);
20
+ var result = !isNaN(parseFloat(str)) && !isNaN(Number(value)) && isFinite(num);
21
+ return Boolean(result);
22
+ }
23
+ var isNotNumeric = bindNot(isNumeric);
24
+
25
+ function numberEquals(value, eq) {
26
+ return isNumeric(value) && isNumeric(eq) && Number(value) === Number(eq);
27
+ }
28
+ var numberNotEquals = bindNot(numberEquals);
29
+
30
+ function lengthEquals(value, arg1) {
31
+ return numberEquals(value.length, arg1);
32
+ }
33
+ var lengthNotEquals = bindNot(lengthEquals);
34
+
35
+ function greaterThan(value, gt) {
36
+ return isNumeric(value) && isNumeric(gt) && Number(value) > Number(gt);
37
+ }
38
+
39
+ function longerThan(value, arg1) {
40
+ return greaterThan(value.length, arg1);
41
+ }
42
+
43
+ /**
44
+ * Creates a cache function
45
+ */
46
+ function createCache(maxSize) {
47
+ if (maxSize === void 0) { maxSize = 1; }
48
+ var cacheStorage = [];
49
+ var cache = function (deps, cacheAction) {
50
+ var cacheHit = cache.get(deps);
51
+ // cache hit is not null
52
+ if (cacheHit)
53
+ return cacheHit[1];
54
+ var result = cacheAction();
55
+ cacheStorage.unshift([deps.concat(), result]);
56
+ if (longerThan(cacheStorage, maxSize))
57
+ cacheStorage.length = maxSize;
58
+ return result;
59
+ };
60
+ // invalidate an item in the cache by its dependencies
61
+ cache.invalidate = function (deps) {
62
+ var index = findIndex(deps);
63
+ if (index > -1)
64
+ cacheStorage.splice(index, 1);
65
+ };
66
+ // Retrieves an item from the cache.
67
+ cache.get = function (deps) {
68
+ return cacheStorage[findIndex(deps)] || null;
69
+ };
70
+ return cache;
71
+ function findIndex(deps) {
72
+ return cacheStorage.findIndex(function (_a) {
73
+ var cachedDeps = _a[0];
74
+ return lengthEquals(deps, cachedDeps.length) &&
75
+ deps.every(function (dep, i) { return dep === cachedDeps[i]; });
76
+ });
77
+ }
78
+ }
79
+
23
80
  function isNull(value) {
24
81
  return value === null;
25
82
  }
@@ -35,39 +92,25 @@
35
92
  }
36
93
  var isNotNullish = bindNot(isNullish);
37
94
 
38
- function isStringValue(v) {
39
- return String(v) === v;
40
- }
41
-
42
- function endsWith(value, arg1) {
43
- return isStringValue(value) && isStringValue(arg1) && value.endsWith(arg1);
44
- }
45
- var doesNotEndWith = bindNot(endsWith);
46
-
47
- function equals(value, arg1) {
48
- return value === arg1;
49
- }
50
- var notEquals = bindNot(equals);
51
-
52
- function isNumeric(value) {
53
- var str = String(value);
54
- var num = Number(value);
55
- var result = !isNaN(parseFloat(str)) && !isNaN(Number(value)) && isFinite(num);
56
- return Boolean(result);
95
+ function asArray(possibleArg) {
96
+ return [].concat(possibleArg);
57
97
  }
58
- var isNotNumeric = bindNot(isNumeric);
59
98
 
60
- function greaterThan(value, gt) {
61
- return isNumeric(value) && isNumeric(gt) && Number(value) > Number(gt);
99
+ function isFunction(value) {
100
+ return typeof value === 'function';
62
101
  }
63
102
 
64
- function numberEquals(value, eq) {
65
- return isNumeric(value) && isNumeric(eq) && Number(value) === Number(eq);
103
+ function optionalFunctionValue(value) {
104
+ var args = [];
105
+ for (var _i = 1; _i < arguments.length; _i++) {
106
+ args[_i - 1] = arguments[_i];
107
+ }
108
+ return isFunction(value) ? value.apply(void 0, args) : value;
66
109
  }
67
- var numberNotEquals = bindNot(numberEquals);
68
110
 
69
- function greaterThanOrEquals(value, gte) {
70
- return numberEquals(value, gte) || greaterThan(value, gte);
111
+ function defaultTo(value, defaultValue) {
112
+ var _a;
113
+ return (_a = optionalFunctionValue(value)) !== null && _a !== void 0 ? _a : optionalFunctionValue(defaultValue);
71
114
  }
72
115
 
73
116
  // The module is named "isArrayValue" since it
@@ -78,66 +121,159 @@
78
121
  }
79
122
  var isNotArray = bindNot(isArray);
80
123
 
81
- function inside(value, arg1) {
82
- if (isArray(arg1)) {
83
- return arg1.indexOf(value) !== -1;
124
+ function last(values) {
125
+ var valuesArray = asArray(values);
126
+ return valuesArray[valuesArray.length - 1];
127
+ }
128
+
129
+ // This is kind of a map/filter in one function.
130
+ // Normally, behaves like a nested-array map,
131
+ // but returning `null` will drop the element from the array
132
+ function transform(array, cb) {
133
+ var res = [];
134
+ for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
135
+ var v = array_1[_i];
136
+ if (isArray(v)) {
137
+ res.push(transform(v, cb));
138
+ }
139
+ else {
140
+ var output = cb(v);
141
+ if (isNotNull(output)) {
142
+ res.push(output);
143
+ }
144
+ }
84
145
  }
85
- // both value and arg1 are strings
86
- if (isStringValue(arg1) && isStringValue(value)) {
87
- return arg1.indexOf(value) !== -1;
146
+ return res;
147
+ }
148
+ function valueAtPath(array, path) {
149
+ return getCurrent(array, path)[last(path)];
150
+ }
151
+ function setValueAtPath(array, path, value) {
152
+ var current = getCurrent(array, path);
153
+ current[last(path)] = value;
154
+ return array;
155
+ }
156
+ function flatten(values) {
157
+ return asArray(values).reduce(function (acc, value) {
158
+ if (isArray(value)) {
159
+ return acc.concat(flatten(value));
160
+ }
161
+ return asArray(acc).concat(value);
162
+ }, []);
163
+ }
164
+ function getCurrent(array, path) {
165
+ var current = array;
166
+ for (var _i = 0, _a = path.slice(0, -1); _i < _a.length; _i++) {
167
+ var p = _a[_i];
168
+ current[p] = defaultTo(current[p], []);
169
+ current = current[p];
88
170
  }
89
- return false;
171
+ return current;
90
172
  }
91
- var notInside = bindNot(inside);
92
173
 
93
- function lessThan(value, lt) {
94
- return isNumeric(value) && isNumeric(lt) && Number(value) < Number(lt);
174
+ function callEach(arr) {
175
+ return arr.forEach(function (fn) { return fn(); });
95
176
  }
96
177
 
97
- function lessThanOrEquals(value, lte) {
98
- return numberEquals(value, lte) || lessThan(value, lte);
178
+ /**
179
+ * A safe hasOwnProperty access
180
+ */
181
+ function hasOwnProperty(obj, key) {
182
+ return Object.prototype.hasOwnProperty.call(obj, key);
99
183
  }
100
184
 
101
- function isBetween(value, min, max) {
102
- return greaterThanOrEquals(value, min) && lessThanOrEquals(value, max);
185
+ function isPromise(value) {
186
+ return value && isFunction(value.then);
103
187
  }
104
- var isNotBetween = bindNot(isBetween);
105
188
 
106
- function isBlank(value) {
107
- return isNullish(value) || (isStringValue(value) && !value.trim());
189
+ var assign = Object.assign;
190
+
191
+ function invariant(condition,
192
+ // eslint-disable-next-line @typescript-eslint/ban-types
193
+ message) {
194
+ if (condition) {
195
+ return;
196
+ }
197
+ // If message is a string object (rather than string literal)
198
+ // Throw the value directly as a string
199
+ // Alternatively, throw an error with the message
200
+ throw message instanceof String
201
+ ? message.valueOf()
202
+ : new Error(message ? optionalFunctionValue(message) : message);
203
+ }
204
+ // eslint-disable-next-line @typescript-eslint/ban-types
205
+ function StringObject(value) {
206
+ return new String(optionalFunctionValue(value));
207
+ }
208
+
209
+ function isStringValue(v) {
210
+ return String(v) === v;
211
+ }
212
+
213
+ function either(a, b) {
214
+ return !!a !== !!b;
108
215
  }
109
- var isNotBlank = bindNot(isBlank);
110
216
 
111
217
  function isBoolean(value) {
112
218
  return !!value === value;
113
219
  }
114
220
 
115
- var isNotBoolean = bindNot(isBoolean);
116
-
117
- /**
118
- * A safe hasOwnProperty access
119
- */
120
- function hasOwnProperty(obj, key) {
121
- return Object.prototype.hasOwnProperty.call(obj, key);
221
+ function deferThrow(message) {
222
+ setTimeout(function () {
223
+ throw new Error(message);
224
+ }, 0);
122
225
  }
123
226
 
124
- function isNumber(value) {
125
- return Boolean(typeof value === 'number');
227
+ function createBus() {
228
+ var listeners = {};
229
+ return {
230
+ emit: function (event, data) {
231
+ listener(event).forEach(function (handler) {
232
+ handler(data);
233
+ });
234
+ },
235
+ on: function (event, handler) {
236
+ listeners[event] = listener(event).concat(handler);
237
+ return {
238
+ off: function () {
239
+ listeners[event] = listener(event).filter(function (h) { return h !== handler; });
240
+ }
241
+ };
242
+ }
243
+ };
244
+ function listener(event) {
245
+ return listeners[event] || [];
246
+ }
126
247
  }
127
- var isNotNumber = bindNot(isNumber);
128
248
 
129
- function lengthEquals(value, arg1) {
130
- return numberEquals(value.length, arg1);
249
+ /**
250
+ * @returns a unique numeric id.
251
+ */
252
+ var genId = (function (n) { return function () {
253
+ return "".concat(n++);
254
+ }; })(0);
255
+
256
+ function mapFirst(array, callback) {
257
+ var broke = false;
258
+ var breakoutValue = null;
259
+ for (var i = 0; i < array.length; i++) {
260
+ callback(array[i], breakout, i);
261
+ if (broke) {
262
+ return breakoutValue;
263
+ }
264
+ }
265
+ function breakout(conditional, value) {
266
+ if (conditional) {
267
+ broke = true;
268
+ breakoutValue = value;
269
+ }
270
+ }
131
271
  }
132
- var lengthNotEquals = bindNot(lengthEquals);
133
272
 
134
273
  function isEmpty(value) {
135
274
  if (!value) {
136
275
  return true;
137
276
  }
138
- else if (isNumber(value)) {
139
- return value === 0;
140
- }
141
277
  else if (hasOwnProperty(value, 'length')) {
142
278
  return lengthEquals(value, 0);
143
279
  }
@@ -148,6 +284,56 @@
148
284
  }
149
285
  var isNotEmpty = bindNot(isEmpty);
150
286
 
287
+ function isPositive(value) {
288
+ return greaterThan(value, 0);
289
+ }
290
+
291
+ function endsWith(value, arg1) {
292
+ return isStringValue(value) && isStringValue(arg1) && value.endsWith(arg1);
293
+ }
294
+ var doesNotEndWith = bindNot(endsWith);
295
+
296
+ function equals(value, arg1) {
297
+ return value === arg1;
298
+ }
299
+ var notEquals = bindNot(equals);
300
+
301
+ function greaterThanOrEquals(value, gte) {
302
+ return numberEquals(value, gte) || greaterThan(value, gte);
303
+ }
304
+
305
+ function inside(value, arg1) {
306
+ if (isArray(arg1)) {
307
+ return arg1.indexOf(value) !== -1;
308
+ }
309
+ // both value and arg1 are strings
310
+ if (isStringValue(arg1) && isStringValue(value)) {
311
+ return arg1.indexOf(value) !== -1;
312
+ }
313
+ return false;
314
+ }
315
+ var notInside = bindNot(inside);
316
+
317
+ function lessThan(value, lt) {
318
+ return isNumeric(value) && isNumeric(lt) && Number(value) < Number(lt);
319
+ }
320
+
321
+ function lessThanOrEquals(value, lte) {
322
+ return numberEquals(value, lte) || lessThan(value, lte);
323
+ }
324
+
325
+ function isBetween(value, min, max) {
326
+ return greaterThanOrEquals(value, min) && lessThanOrEquals(value, max);
327
+ }
328
+ var isNotBetween = bindNot(isBetween);
329
+
330
+ function isBlank(value) {
331
+ return isNullish(value) || (isStringValue(value) && !value.trim());
332
+ }
333
+ var isNotBlank = bindNot(isBlank);
334
+
335
+ var isNotBoolean = bindNot(isBoolean);
336
+
151
337
  /**
152
338
  * Validates that a given value is an even number
153
339
  */
@@ -172,6 +358,11 @@
172
358
  return lessThan(value, 0);
173
359
  }
174
360
 
361
+ function isNumber(value) {
362
+ return Boolean(typeof value === 'number');
363
+ }
364
+ var isNotNumber = bindNot(isNumber);
365
+
175
366
  /**
176
367
  * Validates that a given value is an odd number
177
368
  */
@@ -182,10 +373,6 @@
182
373
  return false;
183
374
  };
184
375
 
185
- function isPositive(value) {
186
- return greaterThan(value, 0);
187
- }
188
-
189
376
  var isNotString = bindNot(isStringValue);
190
377
 
191
378
  function isTruthy(value) {
@@ -206,10 +393,6 @@
206
393
  }
207
394
  var isNotValueOf = bindNot(isValueOf);
208
395
 
209
- function longerThan(value, arg1) {
210
- return greaterThan(value.length, arg1);
211
- }
212
-
213
396
  function longerThanOrEquals(value, arg1) {
214
397
  return greaterThanOrEquals(value.length, arg1);
215
398
  }
@@ -330,33 +513,6 @@
330
513
  }
331
514
  }
332
515
 
333
- function optionalFunctionValue(value) {
334
- var args = [];
335
- for (var _i = 1; _i < arguments.length; _i++) {
336
- args[_i - 1] = arguments[_i];
337
- }
338
- return isFunction(value) ? value.apply(void 0, args) : value;
339
- }
340
-
341
- function defaultTo(callback, defaultValue) {
342
- var _a;
343
- return (_a = optionalFunctionValue(callback)) !== null && _a !== void 0 ? _a : defaultValue;
344
- }
345
-
346
- function invariant(condition,
347
- // eslint-disable-next-line @typescript-eslint/ban-types
348
- message) {
349
- if (condition) {
350
- return;
351
- }
352
- // If message is a string object (rather than string literal)
353
- // Throw the value directly as a string
354
- // Alternatively, throw an error with the message
355
- throw message instanceof String
356
- ? message.valueOf()
357
- : new Error(message ? optionalFunctionValue(message) : message);
358
- }
359
-
360
516
  // eslint-disable-next-line max-lines-per-function
361
517
  function createContext(init) {
362
518
  var storage = { ancestry: [] };
@@ -367,8 +523,9 @@
367
523
  useX: useX
368
524
  };
369
525
  function useX(errorMessage) {
370
- invariant(storage.ctx, defaultTo(errorMessage, 'Context was used after it was closed'));
371
- return storage.ctx;
526
+ var ctx = use();
527
+ invariant(ctx, defaultTo(errorMessage, 'Context was used after it was closed'));
528
+ return ctx;
372
529
  }
373
530
  function run(ctxRef, fn) {
374
531
  var _a;
@@ -531,32 +688,17 @@
531
688
  for (var _i = 0; _i < arguments.length; _i++) {
532
689
  args[_i] = arguments[_i];
533
690
  }
534
- var transformedResult = transformResult.apply(void 0, __spreadArray([ctx.run({ value: value }, function () { return rule.apply(void 0, __spreadArray([value], args, false)); }),
535
- ruleName,
536
- value], args, false));
537
- invariant(transformedResult.pass, isEmpty(transformedResult.message)
691
+ var transformedResult = ctx.run({ value: value }, function () {
692
+ return transformResult.apply(void 0, __spreadArray([rule.apply(void 0, __spreadArray([value], args, false)), ruleName, value], args, false));
693
+ });
694
+ invariant(transformedResult.pass, isNullish(transformedResult.message)
538
695
  ? "enforce/".concat(ruleName, " failed with ").concat(JSON.stringify(value))
539
- : new String(transformedResult.message));
696
+ : StringObject(transformedResult.message));
540
697
  return target;
541
698
  };
542
699
  }
543
700
  }
544
701
 
545
- function mapFirst(array, callback) {
546
- var broke = false;
547
- var breakoutValue = null;
548
- for (var i = 0; i < array.length; i++) {
549
- callback(array[i], breakout, i);
550
- if (broke) {
551
- return breakoutValue;
552
- }
553
- }
554
- function breakout(value) {
555
- broke = true;
556
- breakoutValue = value;
557
- }
558
- }
559
-
560
702
  // eslint-disable-next-line max-lines-per-function
561
703
  function genEnforceLazy(key) {
562
704
  var registeredRules = [];
@@ -579,9 +721,7 @@
579
721
  return defaultToPassing(mapFirst(registeredRules, function (rule, breakout) {
580
722
  var _a;
581
723
  var res = ctx.run({ value: value }, function () { return rule(value); });
582
- if (!res.pass) {
583
- breakout(ruleReturn(!!res.pass, (_a = optionalFunctionValue(lazyMessage, value, res.message)) !== null && _a !== void 0 ? _a : res.message));
584
- }
724
+ breakout(!res.pass, ruleReturn(!!res.pass, (_a = optionalFunctionValue(lazyMessage, value, res.message)) !== null && _a !== void 0 ? _a : res.message));
585
725
  }));
586
726
  },
587
727
  test: function (value) { return proxy.run(value).pass; },
@@ -619,160 +759,62 @@
619
759
  *
620
760
  * Enforce has two main interfaces
621
761
  * 1. eager
622
- * 2. lazy
623
- *
624
- * The eager interface is the most commonly used, and the easier to understand.
625
- * It throws an error when a rule is not satisfied.
626
- * The eager interface is declared in enforceEager.ts and it is quite simple to understand.
627
- * enforce is called with a value, and the return value is a proxy object that points back to all the rules.
628
- * When a rule is called, the value is mapped as its first argument, and if the rule passes, the same
629
- * proxy object is returned. Otherwise, an error is thrown.
630
- *
631
- * The lazy interface works quite differently. It is declared in genEnforceLazy.ts.
632
- * Rather than calling enforce directly, the lazy interface has all the rules as "methods" (only by proxy).
633
- * Calling the first function in the chain will initialize an array of calls. It stores the different rule calls
634
- * and the parameters passed to them. None of the rules are called yet.
635
- * The rules are only invoked in sequence once either of these chained functions are called:
636
- * 1. test(value)
637
- * 2. run(value)
638
- *
639
- * Calling run or test will call all the rules in sequence, with the difference that test will only return a boolean value,
640
- * while run will return an object with the validation result and an optional message created by the rule.
641
- */
642
- function genEnforce() {
643
- var target = {
644
- context: function () { return ctx.useX(); },
645
- extend: function (customRules) {
646
- assign(baseRules, customRules);
647
- handleNoProxy(); // TODO: REMOVE when we stop supporting ES5
648
- }
649
- };
650
- handleNoProxy();
651
- return new Proxy(assign(enforceEager, target), {
652
- get: function (target, key) {
653
- if (key in target) {
654
- return target[key];
655
- }
656
- if (!getRule(key)) {
657
- return;
658
- }
659
- // Only on the first rule access - start the chain of calls
660
- return genEnforceLazy(key);
661
- }
662
- });
663
- function handleNoProxy() {
664
- if (!isProxySupported()) {
665
- eachEnforceRule(function (ruleName) {
666
- // Only on the first rule access - start the chain of calls
667
- target[ruleName] = genEnforceLazy(ruleName);
668
- });
669
- return assign(enforceEager, target);
670
- }
671
- }
672
- }
673
- var enforce = genEnforce();
674
-
675
- /**
676
- * @returns a unique numeric id.
677
- */
678
- var genId = (function (n) { return function () {
679
- return "".concat(n++);
680
- }; })(0);
681
-
682
- function shouldUseErrorAsMessage(message, error) {
683
- // kind of cheating with this safe guard, but it does the job
684
- return isUndefined(message) && isStringValue(error);
685
- }
686
-
687
- function asArray(possibleArg) {
688
- return [].concat(possibleArg);
689
- }
690
-
691
- /**
692
- * Creates a cache function
693
- */
694
- function createCache(maxSize) {
695
- if (maxSize === void 0) { maxSize = 1; }
696
- var cacheStorage = [];
697
- var cache = function (deps, cacheAction) {
698
- var cacheHit = cache.get(deps);
699
- // cache hit is not null
700
- if (cacheHit)
701
- return cacheHit[1];
702
- var result = cacheAction();
703
- cacheStorage.unshift([deps.concat(), result]);
704
- if (longerThan(cacheStorage, maxSize))
705
- cacheStorage.length = maxSize;
706
- return result;
707
- };
708
- // invalidate an item in the cache by its dependencies
709
- cache.invalidate = function (deps) {
710
- var index = findIndex(deps);
711
- if (index > -1)
712
- cacheStorage.splice(index, 1);
713
- };
714
- // Retrieves an item from the cache.
715
- cache.get = function (deps) {
716
- return cacheStorage[findIndex(deps)] || null;
717
- };
718
- return cache;
719
- function findIndex(deps) {
720
- return cacheStorage.findIndex(function (_a) {
721
- var cachedDeps = _a[0];
722
- return lengthEquals(deps, cachedDeps.length) &&
723
- deps.every(function (dep, i) { return dep === cachedDeps[i]; });
724
- });
725
- }
726
- }
727
-
728
- function last(values) {
729
- var valuesArray = asArray(values);
730
- return valuesArray[valuesArray.length - 1];
731
- }
732
-
733
- // This is kind of a map/filter in one function.
734
- // Normally, behaves like a nested-array map,
735
- // but returning `null` will drop the element from the array
736
- function transform(array, cb) {
737
- var res = [];
738
- for (var _i = 0, array_1 = array; _i < array_1.length; _i++) {
739
- var v = array_1[_i];
740
- if (isArray(v)) {
741
- res.push(transform(v, cb));
762
+ * 2. lazy
763
+ *
764
+ * The eager interface is the most commonly used, and the easier to understand.
765
+ * It throws an error when a rule is not satisfied.
766
+ * The eager interface is declared in enforceEager.ts and it is quite simple to understand.
767
+ * enforce is called with a value, and the return value is a proxy object that points back to all the rules.
768
+ * When a rule is called, the value is mapped as its first argument, and if the rule passes, the same
769
+ * proxy object is returned. Otherwise, an error is thrown.
770
+ *
771
+ * The lazy interface works quite differently. It is declared in genEnforceLazy.ts.
772
+ * Rather than calling enforce directly, the lazy interface has all the rules as "methods" (only by proxy).
773
+ * Calling the first function in the chain will initialize an array of calls. It stores the different rule calls
774
+ * and the parameters passed to them. None of the rules are called yet.
775
+ * The rules are only invoked in sequence once either of these chained functions are called:
776
+ * 1. test(value)
777
+ * 2. run(value)
778
+ *
779
+ * Calling run or test will call all the rules in sequence, with the difference that test will only return a boolean value,
780
+ * while run will return an object with the validation result and an optional message created by the rule.
781
+ */
782
+ function genEnforce() {
783
+ var target = {
784
+ context: function () { return ctx.useX(); },
785
+ extend: function (customRules) {
786
+ assign(baseRules, customRules);
787
+ handleNoProxy(); // TODO: REMOVE when we stop supporting ES5
742
788
  }
743
- else {
744
- var output = cb(v);
745
- if (isNotNull(output)) {
746
- res.push(output);
789
+ };
790
+ handleNoProxy();
791
+ return new Proxy(assign(enforceEager, target), {
792
+ get: function (target, key) {
793
+ if (key in target) {
794
+ return target[key];
747
795
  }
796
+ if (!getRule(key)) {
797
+ return;
798
+ }
799
+ // Only on the first rule access - start the chain of calls
800
+ return genEnforceLazy(key);
748
801
  }
749
- }
750
- return res;
751
- }
752
- function valueAtPath(array, path) {
753
- return getCurrent(array, path)[last(path)];
754
- }
755
- function setValueAtPath(array, path, value) {
756
- var current = getCurrent(array, path);
757
- current[last(path)] = value;
758
- return array;
759
- }
760
- function flatten(values) {
761
- return asArray(values).reduce(function (acc, value) {
762
- if (isArray(value)) {
763
- return acc.concat(flatten(value));
802
+ });
803
+ function handleNoProxy() {
804
+ if (!isProxySupported()) {
805
+ eachEnforceRule(function (ruleName) {
806
+ // Only on the first rule access - start the chain of calls
807
+ target[ruleName] = genEnforceLazy(ruleName);
808
+ });
809
+ return assign(enforceEager, target);
764
810
  }
765
- return asArray(acc).concat(value);
766
- }, []);
767
- }
768
- function getCurrent(array, path) {
769
- var current = array;
770
- for (var _i = 0, _a = path.slice(0, -1); _i < _a.length; _i++) {
771
- var p = _a[_i];
772
- current[p] = defaultTo(current[p], []);
773
- current = current[p];
774
811
  }
775
- return current;
812
+ }
813
+ var enforce = genEnforce();
814
+
815
+ function shouldUseErrorAsMessage(message, error) {
816
+ // kind of cheating with this safe guard, but it does the job
817
+ return isUndefined(message) && isStringValue(error);
776
818
  }
777
819
 
778
820
  var IsolateTypes;
@@ -813,80 +855,6 @@
813
855
  }
814
856
  }
815
857
 
816
- function deferThrow(message) {
817
- setTimeout(function () {
818
- throw new Error(message);
819
- }, 0);
820
- }
821
-
822
- function usePrevKeys() {
823
- var prev = useTestObjects()[0].prev;
824
- return asArray(getCurrent(prev, useCurrentPath())).reduce(function (prevKeys, testObject) {
825
- if (!(testObject instanceof VestTest)) {
826
- return prevKeys;
827
- }
828
- if (isNullish(testObject.key)) {
829
- return prevKeys;
830
- }
831
- prevKeys[testObject.key] = testObject;
832
- return prevKeys;
833
- }, {});
834
- }
835
- function usePrevTestByKey(key) {
836
- var prev = context.useX().isolate.keys.prev;
837
- return prev[key];
838
- }
839
- function useRetainTestKey(key, testObject) {
840
- var context$1 = context.useX();
841
- var current = context$1.isolate.keys.current;
842
- if (isNullish(current[key])) {
843
- current[key] = testObject;
844
- }
845
- else {
846
- deferThrow("Encountered the same test key \"".concat(key, "\" twice. This may lead to tests overriding each other's results, or to tests being unexpectedly omitted."));
847
- }
848
- }
849
-
850
- function isolate(_a, callback) {
851
- var _b = _a.type, type = _b === void 0 ? IsolateTypes.DEFAULT : _b;
852
- invariant(isFunction(callback));
853
- // Generate a new Isolate layer, with its own cursor
854
- var isolate = generateIsolate(type, useCurrentPath());
855
- var output = context.run({ isolate: isolate }, function () {
856
- isolate.keys.prev = usePrevKeys();
857
- useSetTests(function (tests) { return setValueAtPath(tests, isolate.path, []); });
858
- var res = callback();
859
- return res;
860
- });
861
- // Move the parent cursor forward once we're done
862
- useCursor().next();
863
- return output;
864
- }
865
- /**
866
- * @returns {Isolate} The current isolate layer
867
- */
868
- function useIsolate() {
869
- return context.useX().isolate;
870
- }
871
- /**
872
- * @returns {boolean} Whether or not the current isolate allows tests to be reordered
873
- */
874
- function shouldAllowReorder() {
875
- return context.useX().isolate.type === IsolateTypes.EACH;
876
- }
877
- /**
878
- * @returns {number[]} The current cursor path of the isolate tree
879
- */
880
- function useCurrentPath() {
881
- var isolate = useIsolate();
882
- return isolate.path.concat(isolate.cursor.current());
883
- }
884
- /**
885
- * @returns {IsolateCursor} The cursor object for the current isolate
886
- */
887
- function useCursor() {
888
- return useIsolate().cursor;
889
- }
890
858
  function generateIsolate(type, path) {
891
859
  if (path === void 0) { path = []; }
892
860
  return {
@@ -1212,6 +1180,74 @@
1212
1180
  };
1213
1181
  }
1214
1182
 
1183
+ function usePrevKeys() {
1184
+ var prev = useTestObjects()[0].prev;
1185
+ return asArray(getCurrent(prev, useCurrentPath())).reduce(function (prevKeys, testObject) {
1186
+ if (!(testObject instanceof VestTest)) {
1187
+ return prevKeys;
1188
+ }
1189
+ if (isNullish(testObject.key)) {
1190
+ return prevKeys;
1191
+ }
1192
+ prevKeys[testObject.key] = testObject;
1193
+ return prevKeys;
1194
+ }, {});
1195
+ }
1196
+ function usePrevTestByKey(key) {
1197
+ var prev = useIsolate().keys.prev;
1198
+ return prev[key];
1199
+ }
1200
+ function useRetainTestKey(key, testObject) {
1201
+ var current = useIsolate().keys.current;
1202
+ if (isNullish(current[key])) {
1203
+ current[key] = testObject;
1204
+ }
1205
+ else {
1206
+ deferThrow("Encountered the same test key \"".concat(key, "\" twice. This may lead to tests overriding each other's results, or to tests being unexpectedly omitted."));
1207
+ }
1208
+ }
1209
+
1210
+ function isolate(_a, callback) {
1211
+ var _b = _a.type, type = _b === void 0 ? IsolateTypes.DEFAULT : _b;
1212
+ invariant(isFunction(callback));
1213
+ // Generate a new Isolate layer, with its own cursor
1214
+ var isolate = generateIsolate(type, useCurrentPath());
1215
+ var output = context.run({ isolate: isolate }, function () {
1216
+ isolate.keys.prev = usePrevKeys();
1217
+ useSetTests(function (tests) { return setValueAtPath(tests, isolate.path, []); });
1218
+ var res = callback();
1219
+ return res;
1220
+ });
1221
+ // Move the parent cursor forward once we're done
1222
+ useCursor().next();
1223
+ return output;
1224
+ }
1225
+ /**
1226
+ * @returns {Isolate} The current isolate layer
1227
+ */
1228
+ function useIsolate() {
1229
+ return context.useX().isolate;
1230
+ }
1231
+ /**
1232
+ * @returns {boolean} Whether or not the current isolate allows tests to be reordered
1233
+ */
1234
+ function shouldAllowReorder() {
1235
+ return useIsolate().type === IsolateTypes.EACH;
1236
+ }
1237
+ /**
1238
+ * @returns {number[]} The current cursor path of the isolate tree
1239
+ */
1240
+ function useCurrentPath() {
1241
+ var isolate = useIsolate();
1242
+ return isolate.path.concat(isolate.cursor.current());
1243
+ }
1244
+ /**
1245
+ * @returns {IsolateCursor} The cursor object for the current isolate
1246
+ */
1247
+ function useCursor() {
1248
+ return useIsolate().cursor;
1249
+ }
1250
+
1215
1251
  var Severity;
1216
1252
  (function (Severity) {
1217
1253
  Severity["WARNINGS"] = "warnings";
@@ -1240,10 +1276,6 @@
1240
1276
  return testObject.groupName === groupName;
1241
1277
  }
1242
1278
 
1243
- function either(a, b) {
1244
- return !!a !== !!b;
1245
- }
1246
-
1247
1279
  /**
1248
1280
  * Checks that a given test object matches the currently specified severity level
1249
1281
  */
@@ -1682,28 +1714,6 @@
1682
1714
  });
1683
1715
  }
1684
1716
 
1685
- function createBus() {
1686
- var listeners = {};
1687
- return {
1688
- emit: function (event, data) {
1689
- listener(event).forEach(function (handler) {
1690
- handler(data);
1691
- });
1692
- },
1693
- on: function (event, handler) {
1694
- listeners[event] = listener(event).concat(handler);
1695
- return {
1696
- off: function () {
1697
- listeners[event] = listener(event).filter(function (h) { return h !== handler; });
1698
- }
1699
- };
1700
- }
1701
- };
1702
- function listener(event) {
1703
- return listeners[event] || [];
1704
- }
1705
- }
1706
-
1707
1717
  function omitOptionalFields() {
1708
1718
  var optionalFields = useOptionalFields()[0];
1709
1719
  if (isEmpty(optionalFields)) {
@@ -1746,10 +1756,6 @@
1746
1756
  });
1747
1757
  }
1748
1758
 
1749
- function callEach(arr) {
1750
- return arr.forEach(function (fn) { return fn(); });
1751
- }
1752
-
1753
1759
  /**
1754
1760
  * Runs done callback per field when async tests are finished running.
1755
1761
  */
@@ -1771,10 +1777,10 @@
1771
1777
 
1772
1778
  // eslint-disable-next-line max-lines-per-function
1773
1779
  function initBus() {
1774
- var bus = createBus();
1780
+ var vestBus = createBus();
1775
1781
  // Report a the completion of a test. There may be other tests with the same
1776
1782
  // name that are still running, or not yet started.
1777
- bus.on(Events.TEST_COMPLETED, function (testObject) {
1783
+ vestBus.on(Events.TEST_COMPLETED, function (testObject) {
1778
1784
  if (testObject.isCanceled()) {
1779
1785
  return;
1780
1786
  }
@@ -1782,21 +1788,21 @@
1782
1788
  runFieldCallbacks(testObject.fieldName);
1783
1789
  if (!hasRemainingTests()) {
1784
1790
  // When no more tests are running, emit the done event
1785
- bus.emit(Events.ALL_RUNNING_TESTS_FINISHED);
1791
+ vestBus.emit(Events.ALL_RUNNING_TESTS_FINISHED);
1786
1792
  }
1787
1793
  });
1788
1794
  // Report that the suite completed its synchronous test run.
1789
1795
  // Async operations may still be running.
1790
- bus.on(Events.SUITE_CALLBACK_DONE_RUNNING, function () {
1796
+ vestBus.on(Events.SUITE_CALLBACK_DONE_RUNNING, function () {
1791
1797
  // Remove tests that are optional and need to be omitted
1792
1798
  omitOptionalFields();
1793
1799
  });
1794
1800
  // Called when all the tests, including async, are done running
1795
- bus.on(Events.ALL_RUNNING_TESTS_FINISHED, function () {
1801
+ vestBus.on(Events.ALL_RUNNING_TESTS_FINISHED, function () {
1796
1802
  runDoneCallbacks();
1797
1803
  });
1798
1804
  // Removes a certain field from the state.
1799
- bus.on(Events.REMOVE_FIELD, function (fieldName) {
1805
+ vestBus.on(Events.REMOVE_FIELD, function (fieldName) {
1800
1806
  useEachTestObject(function (testObject) {
1801
1807
  if (matchingFieldName(testObject, fieldName)) {
1802
1808
  testObject.cancel();
@@ -1805,14 +1811,14 @@
1805
1811
  });
1806
1812
  });
1807
1813
  // Resets a certain field in the state.
1808
- bus.on(Events.RESET_FIELD, function (fieldName) {
1814
+ vestBus.on(Events.RESET_FIELD, function (fieldName) {
1809
1815
  useEachTestObject(function (testObject) {
1810
1816
  if (matchingFieldName(testObject, fieldName)) {
1811
1817
  testObject.reset();
1812
1818
  }
1813
1819
  });
1814
1820
  });
1815
- return bus;
1821
+ return vestBus;
1816
1822
  }
1817
1823
  function useBus() {
1818
1824
  var context$1 = context.useX();
@@ -2133,9 +2139,7 @@
2133
2139
  setMode(Modes.EAGER);
2134
2140
  }
2135
2141
  function shouldSkipBasedOnMode(testObject) {
2136
- if (isEager() && hasErrorsByTestObjects(testObject.fieldName))
2137
- return true;
2138
- return false;
2142
+ return isEager() && hasErrorsByTestObjects(testObject.fieldName);
2139
2143
  }
2140
2144
  function isEager() {
2141
2145
  return isMode(Modes.EAGER);
@@ -2199,10 +2203,6 @@
2199
2203
  }
2200
2204
  }
2201
2205
 
2202
- function isPromise(value) {
2203
- return value && isFunction(value.then);
2204
- }
2205
-
2206
2206
  function isSameProfileTest(testObject1, testObject2) {
2207
2207
  return (testObject1.fieldName === testObject2.fieldName &&
2208
2208
  testObject1.groupName === testObject2.groupName);
@@ -2317,20 +2317,13 @@
2317
2317
  return nextTest;
2318
2318
  }
2319
2319
  function removeAllNextTestsInIsolate() {
2320
- var _a = useTestObjects(), testObjects = _a[0], setTestObjects = _a[1];
2321
- var prevTests = testObjects.prev;
2322
- var current = getCurrent(prevTests, useCurrentPath());
2323
2320
  var cursorAt = useCursor().current();
2324
- current.splice(cursorAt);
2325
2321
  // We actually don't mind mutating the state directly (as can be seen above). There is no harm in it
2326
2322
  // since we're only touching the "prev" state. The reason we still use the setter function is
2327
2323
  // to prevent future headaches if we ever do need to rely on prev-state immutability.
2328
- setTestObjects(function (_a) {
2329
- var current = _a.current;
2330
- return ({
2331
- prev: prevTests,
2332
- current: current
2333
- });
2324
+ useSetTests(function (current) {
2325
+ current.splice(cursorAt);
2326
+ return current;
2334
2327
  });
2335
2328
  }
2336
2329
  function useSetTestAtCursor(testObject) {
@@ -2474,7 +2467,7 @@
2474
2467
  ctx.currentTest.warn();
2475
2468
  }
2476
2469
 
2477
- var VERSION = "4.4.0";
2470
+ var VERSION = "4.4.2-dev-d13b14";
2478
2471
 
2479
2472
  exports.VERSION = VERSION;
2480
2473
  exports.context = context;