n4s 3.1.0 → 4.0.0-dev-e266d9

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 (63) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/LICENSE +1 -2
  3. package/README.md +2 -5
  4. package/compose/package.json +7 -0
  5. package/compounds/package.json +7 -0
  6. package/dist/cjs/compose.development.js +139 -0
  7. package/dist/cjs/compose.js +7 -0
  8. package/dist/cjs/compose.production.js +1 -0
  9. package/dist/cjs/compounds.development.js +132 -0
  10. package/dist/cjs/compounds.js +7 -0
  11. package/dist/cjs/compounds.production.js +1 -0
  12. package/dist/cjs/n4s.development.js +602 -0
  13. package/dist/cjs/n4s.js +7 -0
  14. package/dist/cjs/n4s.production.js +1 -0
  15. package/dist/cjs/package.json +1 -0
  16. package/dist/cjs/schema.development.js +144 -0
  17. package/dist/cjs/schema.js +7 -0
  18. package/dist/cjs/schema.production.js +1 -0
  19. package/dist/es/compose.development.js +137 -0
  20. package/dist/es/compose.production.js +1 -0
  21. package/dist/es/compounds.development.js +130 -0
  22. package/dist/es/compounds.production.js +1 -0
  23. package/dist/es/n4s.development.js +597 -0
  24. package/dist/es/n4s.production.js +1 -0
  25. package/dist/es/package.json +1 -0
  26. package/dist/es/schema.development.js +140 -0
  27. package/dist/es/schema.production.js +1 -0
  28. package/dist/umd/compose.development.js +143 -0
  29. package/dist/umd/compose.production.js +1 -0
  30. package/dist/umd/compounds.development.js +136 -0
  31. package/dist/umd/compounds.production.js +1 -0
  32. package/dist/umd/n4s.development.js +606 -0
  33. package/dist/umd/n4s.production.js +1 -0
  34. package/dist/umd/schema.development.js +148 -0
  35. package/dist/umd/schema.production.js +1 -0
  36. package/docs/README.md +2 -5
  37. package/docs/_sidebar.md +0 -1
  38. package/docs/external.md +1 -28
  39. package/package.json +129 -53
  40. package/schema/package.json +7 -0
  41. package/tsconfig.json +8 -0
  42. package/types/compose.d.ts +134 -0
  43. package/types/compounds.d.ts +146 -0
  44. package/types/n4s.d.ts +167 -0
  45. package/types/schema.d.ts +151 -0
  46. package/config/jest/jest.setup.js +0 -14
  47. package/config/rollup/enforce.js +0 -8
  48. package/config/rollup/rollup.config.js +0 -3
  49. package/docs/compound.md +0 -187
  50. package/docs/custom.md +0 -52
  51. package/docs/template.md +0 -53
  52. package/esm/n4s.es.development.js +0 -1142
  53. package/esm/n4s.es.production.js +0 -1142
  54. package/esm/n4s.es.production.min.js +0 -1
  55. package/esm/package.json +0 -1
  56. package/jest.config.js +0 -3
  57. package/n4s.cjs.development.js +0 -1144
  58. package/n4s.cjs.production.js +0 -1144
  59. package/n4s.cjs.production.min.js +0 -1
  60. package/n4s.js +0 -7
  61. package/n4s.umd.development.js +0 -1231
  62. package/n4s.umd.production.js +0 -1231
  63. package/n4s.umd.production.min.js +0 -1
@@ -1,1144 +0,0 @@
1
- 'use strict';
2
-
3
- var assign = Object.assign;
4
-
5
- /**
6
- * Stores values and configuration passed down to compound rules.
7
- *
8
- * @param {Object} content
9
- */
10
-
11
- function EnforceContext(content) {
12
- assign(this, content);
13
- }
14
- /**
15
- * Sets an EnforceContext config `failFast`
16
- *
17
- * @param {Boolean} failFast
18
- * @return {EnforceContext}
19
- */
20
-
21
- EnforceContext.prototype.setFailFast = function (failFast) {
22
- this.failFast = !!failFast;
23
- return this;
24
- };
25
- /**
26
- * Extracts the literal value from an EnforceContext object
27
- * @param {*} value
28
- * @return {*}
29
- */
30
-
31
-
32
- EnforceContext.unwrap = function unwrap(value) {
33
- return EnforceContext.is(value) ? value.value : value;
34
- };
35
- /**
36
- * Wraps a literal value within a context.
37
- * @param {*} value
38
- * @return {EnforceContext}
39
- */
40
-
41
-
42
- EnforceContext.wrap = function wrap(value) {
43
- return EnforceContext.is(value) ? value : new EnforceContext({
44
- value
45
- });
46
- };
47
- /**
48
- * Checks whether a given value is an EnforceContext instance
49
- *
50
- * @param {*} value
51
- * @returns {boolean}
52
- */
53
-
54
-
55
- EnforceContext.is = function is(value) {
56
- return value instanceof EnforceContext;
57
- };
58
-
59
- /**
60
- * A safe hasOwnProperty access
61
- */
62
- function hasOwnProperty(obj, key) {
63
- return Object.prototype.hasOwnProperty.call(obj, key);
64
- }
65
-
66
- function bindNot(fn) {
67
- return function () {
68
- return !fn.apply(this, arguments);
69
- };
70
- }
71
-
72
- function isBoolean(value) {
73
- return !!value === value;
74
- }
75
-
76
- const isNotBoolean = bindNot(isBoolean);
77
-
78
- function isNumeric(value) {
79
- const result = !isNaN(parseFloat(value)) && !isNaN(Number(value)) && isFinite(value);
80
- return Boolean(result);
81
- }
82
- const isNotNumeric = bindNot(isNumeric);
83
-
84
- function lengthEquals(value, arg1) {
85
- return value.length === Number(arg1);
86
- }
87
- const lengthNotEquals = bindNot(lengthEquals);
88
-
89
- function isEmpty(value) {
90
- if (!value) {
91
- return true;
92
- } else if (isNumeric(value)) {
93
- return value === 0;
94
- } else if (hasOwnProperty(value, 'length')) {
95
- return lengthEquals(value, 0);
96
- } else if (typeof value === 'object') {
97
- return lengthEquals(Object.keys(value), 0);
98
- }
99
-
100
- return true;
101
- }
102
- const isNotEmpty = bindNot(isEmpty);
103
-
104
- function isNull(value) {
105
- return value === null;
106
- }
107
- const isNotNull = bindNot(isNull);
108
-
109
- function isUndefined(value) {
110
- return value === undefined;
111
- }
112
- const isNotUndefined = bindNot(isUndefined);
113
-
114
- const HAS_WARNINGS = 'hasWarnings';
115
- const HAS_ERRORS = 'hasErrors';
116
-
117
- /**
118
- * Stores a rule result in an easy to inspect and manipulate structure.
119
- *
120
- * @param {boolean|RuleResult} ruleRunResult
121
- */
122
-
123
- function RuleResult(ruleRunResult) {
124
- if (isUndefined(ruleRunResult)) {
125
- return;
126
- }
127
-
128
- if (isBoolean(ruleRunResult)) {
129
- this.setFailed(!ruleRunResult);
130
- } else {
131
- this.extend(ruleRunResult);
132
- }
133
- }
134
- /**
135
- * Determines whether a given value is a RuleResult instance
136
- * @param {*} res
137
- * @return {boolean}
138
- */
139
-
140
- RuleResult.is = function (res) {
141
- return res instanceof RuleResult;
142
- };
143
- /**
144
- * Marks the current result object as an array
145
- */
146
-
147
-
148
- RuleResult.prototype.asArray = function () {
149
- this.isArray = true;
150
- return this;
151
- };
152
- /**
153
- * @param {string} key
154
- * @param {value} value
155
- * @return {RuleResult} current instance
156
- */
157
-
158
-
159
- RuleResult.prototype.setAttribute = function (key, value) {
160
- this[key] = value;
161
- return this;
162
- };
163
- /**
164
- * @param {boolean} failed
165
- * @return {RuleResult} current instance
166
- */
167
-
168
-
169
- RuleResult.prototype.setFailed = function (failed) {
170
- this.setAttribute(this.warn ? HAS_WARNINGS : HAS_ERRORS, failed);
171
- return this.setAttribute('failed', failed);
172
- };
173
- /**
174
- * Adds a nested result object
175
- *
176
- * @param {string} key
177
- * @param {RuleResult} child
178
- */
179
-
180
-
181
- RuleResult.prototype.setChild = function (key, child) {
182
- if (isNull(child)) {
183
- return null;
184
- }
185
-
186
- const isWarning = this[HAS_WARNINGS] || child[HAS_WARNINGS] || child.warn || this.warn;
187
- this.setAttribute(HAS_WARNINGS, isWarning && child.failed || false);
188
- this.setAttribute(HAS_ERRORS, this[HAS_ERRORS] || child[HAS_ERRORS] || !isWarning && child.failed || false);
189
- this.setFailed(this.failed || child.failed);
190
- this.children = this.children || {};
191
- this.children[key] = child;
192
- return child;
193
- };
194
- /**
195
- * Retrieves a child by its key
196
- *
197
- * @param {string} key
198
- * @return {RuleResult|undefined}
199
- */
200
-
201
-
202
- RuleResult.prototype.getChild = function (key) {
203
- return (this.children || {})[key];
204
- };
205
- /**
206
- * Extends current instance with a new provided result
207
- * @param {Boolean|RuleResult} newRes
208
- */
209
-
210
-
211
- RuleResult.prototype.extend = function (newRes) {
212
- if (isNull(newRes)) {
213
- return this;
214
- }
215
-
216
- const res = RuleResult.is(newRes) ? newRes : new RuleResult().setAttribute('warn', !!this.warn).setFailed(!newRes);
217
- const failed = this.failed || res.failed;
218
- const children = mergeChildren(res, this).children;
219
- assign(this, res);
220
-
221
- if (!isEmpty(children)) {
222
- this.children = children;
223
- }
224
-
225
- this.setFailed(failed);
226
- this.setAttribute(HAS_WARNINGS, !!(this[HAS_WARNINGS] || res[HAS_WARNINGS]));
227
- this.setAttribute(HAS_ERRORS, !!(this[HAS_ERRORS] || res[HAS_ERRORS]));
228
- };
229
-
230
- Object.defineProperty(RuleResult.prototype, 'pass', {
231
- get() {
232
- return !this.failed;
233
- }
234
-
235
- });
236
- /**
237
- * Deeply merge the nested children of compound rules
238
- *
239
- * @param {?RuleResult} base
240
- * @param {?RuleResult} add
241
- * @return {RuleResult}
242
- */
243
-
244
- function mergeChildren(base, add) {
245
- const isRuleResultBase = RuleResult.is(base);
246
- const isRuleResultAdd = RuleResult.is(add); // If both base and add are result objects
247
-
248
- if (isRuleResultBase && isRuleResultAdd) {
249
- // Use failed if either is failing
250
- base.setFailed(base.failed || add.failed); // If neither has a children object, or the children object is
251
-
252
- if (isEmpty(base.children) && isEmpty(add.children)) {
253
- return base;
254
- } // If both have a children object
255
-
256
-
257
- if (base.children && add.children) {
258
- // Merge all the "right side" children back to base
259
- for (const key in base.children) {
260
- mergeChildren(base.children[key], add.children[key]);
261
- } // If a child exists in "add" but not in "base", just copy the child as is
262
-
263
-
264
- for (const key in add.children) {
265
- if (!hasOwnProperty(base.children, key)) {
266
- base.setChild(key, add.children[key]);
267
- }
268
- } // Return the modified base object
269
-
270
-
271
- return base; // If base has no children (but add does)
272
- } else if (!base.children) {
273
- // Use add's children
274
- base.children = add.children; // If add has no children
275
- } else if (!add.children) {
276
- // return base as is
277
- return base;
278
- } // If only base is `RuleResult`
279
-
280
- } else if (isRuleResultBase) {
281
- // Return base as is
282
- return base; // If only add is RuleResult
283
- } else if (isRuleResultAdd) {
284
- // Return add as is
285
- return add;
286
- } // That's a weird case. Let's fail. Very unlikely.
287
-
288
-
289
- return new RuleResult(false);
290
- }
291
-
292
- const RUN_RULE = 'run';
293
- const TEST_RULE = 'test';
294
- const MODE_ALL = 'all';
295
- const MODE_ONE = 'one';
296
- const MODE_ANY = 'any';
297
-
298
- function isFunction (v) {
299
- return typeof v === 'function';
300
- }
301
-
302
- function asArray(possibleArg) {
303
- return [].concat(possibleArg);
304
- }
305
-
306
- /**
307
- * Determines whether we should bail out of an enforcement.
308
- *
309
- * @param {EnforceContext} ctx
310
- * @param {RuleResult} result
311
- */
312
-
313
- function shouldFailFast(ctx, result) {
314
- if (result.pass || result.warn) {
315
- return false;
316
- }
317
-
318
- return !!EnforceContext.is(ctx) && ctx.failFast;
319
- }
320
-
321
- /**
322
- * Runs multiple enforce rules that are passed to compounds.
323
- * Example: enforce.allOf(enforce.ruleOne(), enforce.ruleTwo().ruleThree())
324
- *
325
- * @param {{run: Function}[]} ruleGroups
326
- * @param {*} value
327
- * @return {RuleResult}
328
- */
329
-
330
- function runLazyRules(ruleGroups, value) {
331
- const result = new RuleResult(true);
332
-
333
- for (const chain of asArray(ruleGroups)) {
334
- if (shouldFailFast(value, result)) {
335
- break;
336
- }
337
-
338
- result.extend(runLazyRule(chain, value));
339
- }
340
-
341
- return result;
342
- }
343
- /**
344
- * Runs a single lazy rule
345
- *
346
- * @param {{run: Function}} ruleGroup
347
- * @param {*} value
348
- * @return {boolean|RuleResult}
349
- */
350
-
351
- function runLazyRule(ruleGroup, value) {
352
- return ruleGroup[RUN_RULE](value);
353
- }
354
-
355
- /**
356
- * Runs chains of rules
357
- *
358
- * @param {EnforceContext} value
359
- * @param {[{test: Function, run: Function}]} rules
360
- * @param {RuleResult} options
361
- */
362
-
363
- function runCompoundChain(value, rules, options) {
364
- const result = new RuleResult(true);
365
-
366
- if (isEmpty(rules)) {
367
- result.setFailed(true);
368
- }
369
-
370
- const failedResults = [];
371
- let count = 0;
372
-
373
- for (const chain of rules) {
374
- // Inner result for each iteration
375
- const currentResult = runLazyRule(chain, value);
376
-
377
- if (isNull(currentResult)) {
378
- return null;
379
- }
380
-
381
- const pass = currentResult.pass;
382
-
383
- if (pass) {
384
- count++;
385
- } else {
386
- failedResults.push(currentResult);
387
- }
388
-
389
- if (options) {
390
- // "anyOf" is a special case.
391
- // It shouldn't extend with failed results,
392
- // that's why we continue
393
- if (options.mode === MODE_ANY) {
394
- if (pass) {
395
- result.extend(currentResult);
396
- break;
397
- }
398
-
399
- continue;
400
- }
401
-
402
- result.extend(currentResult); // MODE_ALL: All must pass.
403
- // If one failed, exit.
404
-
405
- if (options.mode === MODE_ALL) {
406
- if (!pass) {
407
- break;
408
- }
409
- } // MODE_ONE: only one must pass.
410
- // If more than one passed, exit.
411
-
412
-
413
- if (options.mode === MODE_ONE) {
414
- result.setFailed(count !== 1);
415
-
416
- if (count > 1) {
417
- break;
418
- }
419
- }
420
- } else {
421
- result.extend(currentResult);
422
-
423
- if (pass) {
424
- break;
425
- }
426
- }
427
- }
428
-
429
- if (result.pass && count === 0) {
430
- result.setFailed(true); // In some cases we do not want to extend failures, for example - in ANY
431
- // when there is a valid response, so we do it before returning
432
-
433
- failedResults.forEach(failedResult => result.extend(failedResult));
434
- }
435
-
436
- return result;
437
- }
438
-
439
- function setFnName(fn, value) {
440
- var _Object$getOwnPropert;
441
-
442
- // Pre ES2015 non standard implementation, "Function.name" is non configurable field
443
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
444
- return (_Object$getOwnPropert = Object.getOwnPropertyDescriptor(fn, 'name')) !== null && _Object$getOwnPropert !== void 0 && _Object$getOwnPropert.configurable ? Object.defineProperty(fn, 'name', {
445
- value
446
- }) : fn;
447
- }
448
-
449
- /**
450
- * ES5 Transpilation increases the size of spread arguments by a lot.
451
- * Wraps a function and passes its spread params as an array.
452
- *
453
- * @param {Function} cb
454
- * @param {String} [fnName]
455
- * @return {Function}
456
- */
457
-
458
- function withArgs(cb, fnName) {
459
- return setFnName(function () {
460
- const args = Array.from(arguments);
461
- const right = args.splice(cb.length - 1);
462
- return cb.apply(null, args.concat([right]));
463
- }, fnName || cb.name);
464
- }
465
-
466
- /**
467
- * Runs a chain of rules, making sure that all assertions pass
468
- *
469
- * @param {EnforceContext} value
470
- * @param {[{test: Function, run: Function}]} ruleChains
471
- * @return {RuleResult}
472
- */
473
-
474
- function allOf(value, rules) {
475
- return runCompoundChain(value, rules, {
476
- mode: MODE_ALL
477
- });
478
- }
479
-
480
- var allOf$1 = withArgs(allOf);
481
-
482
- /**
483
- * Runs chains of rules, making sure
484
- * that at least one assertion passes
485
- *
486
- * @param {EnforceContext} value
487
- * @param {[{test: Function, run: Function}]} ruleChains
488
- * @return {RuleResult}
489
- */
490
-
491
- function anyOf(value, ruleChains) {
492
- return runCompoundChain(value, ruleChains, {
493
- mode: MODE_ANY
494
- });
495
- }
496
-
497
- var anyOf$1 = withArgs(anyOf);
498
-
499
- function isArray(value) {
500
- return Boolean(Array.isArray(value));
501
- }
502
- const isNotArray = bindNot(isArray);
503
-
504
- /**
505
- * Asserts that each element in an array passes
506
- * at least one of the provided rule chain
507
- *
508
- * @param {EnforceContext} value
509
- * @param {[{test: Function, run: Function}]} ruleChains
510
- * @return {RuleResult}
511
- */
512
-
513
- function isArrayOf(value, ruleChains) {
514
- const plainValue = EnforceContext.unwrap(value);
515
- const result = new RuleResult(true).asArray(); // Fails if current value is not an array
516
-
517
- if (isNotArray(plainValue)) {
518
- return result.setFailed(true);
519
- }
520
-
521
- for (let i = 0; i < plainValue.length; i++) {
522
- // Set result per each item in the array
523
- result.setChild(i, runCompoundChain(new EnforceContext({
524
- value: plainValue[i],
525
- obj: plainValue,
526
- key: i
527
- }).setFailFast(value.failFast), ruleChains, {
528
- mode: MODE_ANY
529
- }));
530
- }
531
-
532
- return result;
533
- }
534
-
535
- var isArrayOf$1 = withArgs(isArrayOf);
536
-
537
- /**
538
- * @param {EnforceContext} value
539
- * @param {[{test: Function, run: Function}]} ruleChains
540
- * @return {RuleResult}
541
- */
542
-
543
- function oneOf(value, rules) {
544
- return runCompoundChain(value, rules, {
545
- mode: MODE_ONE
546
- });
547
- }
548
-
549
- var oneOf$1 = withArgs(oneOf);
550
-
551
- /**
552
- * @param {Array} ObjectEntry Object and key leading to current value
553
- * @param {Function[]} rules Rules to validate the value with
554
- */
555
-
556
- function optional(inputObject, ruleGroups) {
557
- const {
558
- obj,
559
- key
560
- } = inputObject; // If current value is not defined, undefined or null
561
- // Pass without further assertions
562
-
563
- if (!hasOwnProperty(obj, key) || isUndefined(obj[key] || isNull(obj[key]))) {
564
- return true;
565
- } // Pass if exists but no assertions
566
-
567
-
568
- if (isEmpty(ruleGroups)) {
569
- return true;
570
- } // Run chain with `all` mode
571
-
572
-
573
- return runCompoundChain(obj[key], ruleGroups, {
574
- mode: MODE_ALL
575
- });
576
- }
577
-
578
- var optional$1 = withArgs(optional);
579
-
580
- /**
581
- * @param {EnforceContext} inputObject Data object that gets validated
582
- * @param {Object} shapeObj Shape definition
583
- * @param {Object} options
584
- * @param {boolean} options.loose Ignore extra keys not defined in shapeObj
585
- */
586
-
587
- function shape(inputObject, shapeObj, options) {
588
- // Extract the object from context
589
- const obj = EnforceContext.unwrap(inputObject); // Create a new result object
590
-
591
- const result = new RuleResult(true); // Iterate over the shape keys
592
-
593
- for (const key in shapeObj) {
594
- const current = shapeObj[key];
595
- const value = obj[key];
596
-
597
- if (shouldFailFast(value, result)) {
598
- break;
599
- } // Set each key in the result object
600
-
601
-
602
- result.setChild(key, runLazyRule(current, new EnforceContext({
603
- value,
604
- obj,
605
- key
606
- }).setFailFast(inputObject.failFast)));
607
- } // If mode is not loose
608
-
609
-
610
- if (!(options || {}).loose) {
611
- // Check that each key in the input object exists in the shape
612
- for (const key in obj) {
613
- if (!hasOwnProperty(shapeObj, key)) {
614
- return result.setFailed(true);
615
- }
616
- }
617
- }
618
-
619
- return result;
620
- }
621
- const loose = (obj, shapeObj) => shape(obj, shapeObj, {
622
- loose: true
623
- });
624
-
625
- var compounds = {
626
- allOf: allOf$1,
627
- anyOf: anyOf$1,
628
- isArrayOf: isArrayOf$1,
629
- loose,
630
- oneOf: oneOf$1,
631
- optional: optional$1,
632
- shape
633
- };
634
-
635
- /**
636
- * Takes a value. If it is a function, runs it and returns the result.
637
- * Otherwise, returns the value as is.
638
- *
639
- * @param {Function|*} value Value to return. Run it if a function.
640
- * @param {Any[]} [args] Arguments to pass if a function
641
- * @return {Any}
642
- */
643
-
644
- function optionalFunctionValue(value, args) {
645
- return isFunction(value) ? value.apply(null, args) : value;
646
- }
647
-
648
- function message(value, msg) {
649
- return optionalFunctionValue(msg, [EnforceContext.unwrap(value)]);
650
- }
651
-
652
- function warn(_, isWarn = true) {
653
- return isWarn;
654
- }
655
-
656
- function when(value, condition, bail) {
657
- const shouldBail = !optionalFunctionValue(condition, [EnforceContext.unwrap(value)].concat(EnforceContext.is(value) ? [value.key, value.obj] : []));
658
- return bail(shouldBail);
659
- }
660
-
661
- var ruleMeta = {
662
- warn,
663
- message,
664
- when
665
- };
666
-
667
- function isString (v) {
668
- return String(v) === v;
669
- }
670
-
671
- function endsWith(value, arg1) {
672
- return isString(value) && isString(arg1) && value.endsWith(arg1);
673
- }
674
- const doesNotEndWith = bindNot(endsWith);
675
-
676
- function equals(value, arg1) {
677
- return value === arg1;
678
- }
679
- const notEquals = bindNot(equals);
680
-
681
- function greaterThan(value, arg1) {
682
- return isNumeric(value) && isNumeric(arg1) && Number(value) > Number(arg1);
683
- }
684
-
685
- function greaterThanOrEquals(value, arg1) {
686
- return isNumeric(value) && isNumeric(arg1) && Number(value) >= Number(arg1);
687
- }
688
-
689
- function inside(value, arg1) {
690
- if (Array.isArray(arg1) && /^[s|n|b]/.test(typeof value)) {
691
- return arg1.indexOf(value) !== -1;
692
- } // both value and arg1 are strings
693
-
694
-
695
- if (isString(arg1) && isString(value)) {
696
- return arg1.indexOf(value) !== -1;
697
- }
698
-
699
- return false;
700
- }
701
- const notInside = bindNot(inside);
702
-
703
- function lessThanOrEquals(value, arg1) {
704
- return isNumeric(value) && isNumeric(arg1) && Number(value) <= Number(arg1);
705
- }
706
-
707
- function isBetween(value, min, max) {
708
- return greaterThanOrEquals(value, min) && lessThanOrEquals(value, max);
709
- }
710
- const isNotBetween = bindNot(isBetween);
711
-
712
- function isBlank(value) {
713
- return typeof value === 'string' && value.trim() === '';
714
- }
715
- const isNotBlank = bindNot(isBlank);
716
-
717
- /**
718
- * Validates that a given value is an even number
719
- * @param {Number|String} value Value to be validated
720
- * @return {Boolean}
721
- */
722
-
723
- const isEven = value => {
724
- if (isNumeric(value)) {
725
- return value % 2 === 0;
726
- }
727
-
728
- return false;
729
- };
730
-
731
- function isNaN$1(value) {
732
- return Number.isNaN(value);
733
- }
734
- const isNotNaN = bindNot(isNaN$1);
735
-
736
- function isNegative(value) {
737
- if (isNumeric(value)) {
738
- return Number(value) < 0;
739
- }
740
-
741
- return false;
742
- }
743
- const isPositive = bindNot(isNegative);
744
-
745
- function isNumber(value) {
746
- return Boolean(typeof value === 'number');
747
- }
748
- const isNotNumber = bindNot(isNumber);
749
-
750
- /**
751
- * Validates that a given value is an odd number
752
- * @param {Number|String} value Value to be validated
753
- * @return {Boolean}
754
- */
755
-
756
- const isOdd = value => {
757
- if (isNumeric(value)) {
758
- return value % 2 !== 0;
759
- }
760
-
761
- return false;
762
- };
763
-
764
- const isNotString = bindNot(isString);
765
-
766
- function isTruthy(value) {
767
- return !!value;
768
- }
769
- const isFalsy = bindNot(isTruthy);
770
-
771
- function lessThan(value, arg1) {
772
- return isNumeric(value) && isNumeric(arg1) && Number(value) < Number(arg1);
773
- }
774
-
775
- function longerThan(value, arg1) {
776
- return value.length > Number(arg1);
777
- }
778
-
779
- function longerThanOrEquals(value, arg1) {
780
- return value.length >= Number(arg1);
781
- }
782
-
783
- function matches(value, regex) {
784
- if (regex instanceof RegExp) {
785
- return regex.test(value);
786
- } else if (isString(regex)) {
787
- return new RegExp(regex).test(value);
788
- } else {
789
- return false;
790
- }
791
- }
792
- const notMatches = bindNot(matches);
793
-
794
- function numberEquals(value, arg1) {
795
- return isNumeric(value) && isNumeric(arg1) && Number(value) === Number(arg1);
796
- }
797
- const numberNotEquals = bindNot(numberEquals);
798
-
799
- function shorterThan(value, arg1) {
800
- return value.length < Number(arg1);
801
- }
802
-
803
- function shorterThanOrEquals(value, arg1) {
804
- return value.length <= Number(arg1);
805
- }
806
-
807
- function startsWith(value, arg1) {
808
- return isString(value) && isString(arg1) && value.startsWith(arg1);
809
- }
810
- const doesNotStartWith = bindNot(startsWith);
811
-
812
- function rules() {
813
- return {
814
- doesNotEndWith,
815
- doesNotStartWith,
816
- endsWith,
817
- equals,
818
- greaterThan,
819
- greaterThanOrEquals,
820
- gt: greaterThan,
821
- gte: greaterThanOrEquals,
822
- inside,
823
- isArray,
824
- isBetween,
825
- isBoolean,
826
- isBlank,
827
- isEmpty,
828
- isEven,
829
- isFalsy,
830
- isNaN: isNaN$1,
831
- isNegative,
832
- isNotArray,
833
- isNotBetween,
834
- isNotBlank,
835
- isNotBoolean,
836
- isNotEmpty,
837
- isNotNaN,
838
- isNotNull,
839
- isNotNumber,
840
- isNotNumeric,
841
- isNotString,
842
- isNotUndefined,
843
- isNull,
844
- isNumber,
845
- isNumeric,
846
- isOdd,
847
- isPositive,
848
- isString,
849
- isTruthy,
850
- isUndefined,
851
- lengthEquals,
852
- lengthNotEquals,
853
- lessThan,
854
- lessThanOrEquals,
855
- longerThan,
856
- longerThanOrEquals,
857
- lt: lessThan,
858
- lte: lessThanOrEquals,
859
- matches,
860
- notEquals,
861
- notInside,
862
- notMatches,
863
- numberEquals,
864
- numberNotEquals,
865
- shorterThan,
866
- shorterThanOrEquals,
867
- startsWith
868
- };
869
- }
870
-
871
- var runtimeRules = assign(rules(), compounds, ruleMeta);
872
-
873
- /**
874
- * Determines whether a given string is a name of a rule
875
- *
876
- * @param {string} name
877
- * @return {boolean}
878
- */
879
-
880
- const isRule = name => hasOwnProperty(runtimeRules, name) && isFunction(runtimeRules[name]);
881
-
882
- const GLOBAL_OBJECT = Function('return this')();
883
-
884
- const proxySupported = () => isFunction(GLOBAL_OBJECT.Proxy);
885
-
886
- function genRuleProxy(target, output) {
887
- if (proxySupported()) {
888
- return new Proxy(target, {
889
- get: (target, fnName) => {
890
- // A faster bailout when we access `run` and `test`
891
- if (hasOwnProperty(target, fnName)) {
892
- return target[fnName];
893
- }
894
-
895
- if (isRule(fnName)) {
896
- return output(fnName);
897
- }
898
-
899
- return target[fnName];
900
- }
901
- });
902
- } else {
903
- /**
904
- * This method is REALLY not recommended as it is slow and iterates over
905
- * all the rules for each direct enforce reference. We only use it as a
906
- * lightweight alternative for the much faster proxy interface
907
- */
908
- for (const fnName in runtimeRules) {
909
- if (!isFunction(target[fnName])) {
910
- Object.defineProperties(target, {
911
- [fnName]: {
912
- get: () => output(fnName)
913
- }
914
- });
915
- }
916
- }
917
-
918
- return target;
919
- }
920
- }
921
-
922
- /**
923
- * Determines whether a given rule is a compound.
924
- *
925
- * @param {Function} rule
926
- * @return {boolean}
927
- */
928
-
929
- function isCompound(rule) {
930
- return hasOwnProperty(compounds, rule.name);
931
- }
932
-
933
- /**
934
- * Creates a rule of lazily called rules.
935
- * Each rule gets added a `.run()` property
936
- * which runs all the accumulated rules in
937
- * the chain against the supplied value
938
- *
939
- * @param {string} ruleName
940
- * @return {{run: Function}}
941
- */
942
-
943
- function bindLazyRule(ruleName) {
944
- const registeredRules = []; // Chained rules
945
-
946
- const meta = []; // Meta properties to add onto the rule context
947
- // Appends a function to the registeredRules array.
948
- // It gets called every time the consumer usess chaining
949
- // so, for example - enforce.isArray() <- this calles addFn
950
-
951
- const addFn = ruleName => {
952
- return withArgs(args => {
953
- const rule = runtimeRules[ruleName]; // Add a meta function
954
-
955
- if (ruleMeta[rule.name] === rule) {
956
- meta.push((value, ruleResult, bail) => {
957
- ruleResult.setAttribute(rule.name, rule(value, args[0], bail));
958
- });
959
- } else {
960
- // Register a rule
961
- registeredRules.push(setFnName(value => {
962
- return rule.apply(null, [// If the rule is compound - wraps the value with context
963
- // Otherwise - unwraps it
964
- isCompound(rule) ? EnforceContext.wrap(value) : EnforceContext.unwrap(value)].concat(args));
965
- }, ruleName));
966
- } // set addFn as the proxy handler
967
-
968
-
969
- const returnvalue = genRuleProxy({}, addFn);
970
-
971
- returnvalue[RUN_RULE] = value => {
972
- const result = new RuleResult(true);
973
- let bailed = false; // Run meta chains
974
-
975
- meta.forEach(fn => {
976
- fn(value, result, shouldBail => bailed = shouldBail);
977
- });
978
-
979
- if (bailed) {
980
- return null;
981
- } // Iterate over all the registered rules
982
- // This runs the function that's inside `addFn`
983
-
984
-
985
- for (const fn of registeredRules) {
986
- try {
987
- result.extend(fn(value)); // If a chained rule fails, exit. We failed.
988
-
989
- if (!result.pass) {
990
- break;
991
- }
992
- } catch (e) {
993
- result.setFailed(true);
994
- break;
995
- }
996
- }
997
-
998
- return result;
999
- };
1000
-
1001
- returnvalue[TEST_RULE] = value => returnvalue[RUN_RULE](EnforceContext.wrap(value).setFailFast(true)).pass;
1002
-
1003
- return returnvalue;
1004
- }, ruleName);
1005
- }; // Returns the initial rule in the chain
1006
-
1007
-
1008
- return addFn(ruleName);
1009
- }
1010
-
1011
- function bindExtend(enforce, Enforce) {
1012
- enforce.extend = customRules => {
1013
- assign(runtimeRules, customRules);
1014
-
1015
- if (!proxySupported()) {
1016
- genRuleProxy(Enforce, bindLazyRule);
1017
- }
1018
-
1019
- return enforce;
1020
- };
1021
- }
1022
-
1023
- /**
1024
- * Throws a timed out error.
1025
- * @param {String} message Error message to display.
1026
- * @param {Error} [type] Alternative Error type.
1027
- */
1028
- const throwError = (message, type = Error) => {
1029
- throw new type(`[${"n4s"}]: ${message}`);
1030
- };
1031
-
1032
- function validateResult(result, rule) {
1033
- // if result is boolean, or if result.pass is boolean
1034
- if (isBoolean(result) || result && isBoolean(result.pass)) {
1035
- return;
1036
- }
1037
-
1038
- throwError(rule.name + 'wrong return value');
1039
- } // for easier testing and mocking
1040
-
1041
- function getDefaultResult(value) {
1042
- return {
1043
- message: new Error(`invalid ${typeof value} value`)
1044
- };
1045
- }
1046
- /**
1047
- * Transform the result of a rule into a standard format
1048
- * @param {string} interfaceName to be used in the messages
1049
- * @param {*} result of the rule
1050
- * @param {Object} options
1051
- * @param {function} options.rule
1052
- * @param {*} options.value
1053
- * @returns {Object} result
1054
- * @returns {string} result.message
1055
- * @returns {boolean} result.pass indicates if the test passes or not
1056
- */
1057
-
1058
- function transformResult(result, {
1059
- rule,
1060
- value
1061
- }) {
1062
- const defaultResult = getDefaultResult(value);
1063
- validateResult(result, rule); // if result is boolean
1064
-
1065
- if (isBoolean(result)) {
1066
- return defaultResult.pass = result, defaultResult;
1067
- } else {
1068
- defaultResult.pass = result.pass;
1069
-
1070
- if (result.message) {
1071
- defaultResult.message = optionalFunctionValue(result.message);
1072
- }
1073
-
1074
- return defaultResult;
1075
- }
1076
- }
1077
-
1078
- /**
1079
- * Run a single rule against enforced value (e.g. `isNumber()`)
1080
- *
1081
- * @param {Function} rule - rule to run
1082
- * @param {Any} value
1083
- * @param {Array} args list of arguments sent from consumer
1084
- * @throws
1085
- */
1086
-
1087
- function runner(rule, value, args = []) {
1088
- let result;
1089
- const isCompoundRule = isCompound(rule);
1090
- const ruleValue = isCompoundRule ? EnforceContext.wrap(value).setFailFast(true) : EnforceContext.unwrap(value);
1091
- result = rule.apply(null, [ruleValue].concat(args));
1092
-
1093
- if (!isCompoundRule) {
1094
- result = transformResult(result, {
1095
- rule,
1096
- value
1097
- });
1098
- }
1099
-
1100
- if (!result.pass) {
1101
- throw result.message;
1102
- }
1103
- }
1104
-
1105
- /**
1106
- * Adds `template` property to enforce.
1107
- *
1108
- * @param {Function} enforce
1109
- */
1110
-
1111
- function bindTemplate(enforce) {
1112
- enforce.template = withArgs(rules => {
1113
- const template = value => {
1114
- runner(runLazyRules.bind(null, rules), value);
1115
- const proxy = genRuleProxy({}, ruleName => withArgs(args => {
1116
- runner(runtimeRules[ruleName], value, args);
1117
- return proxy;
1118
- }));
1119
- return proxy;
1120
- }; // `run` returns a deep ResultObject
1121
-
1122
-
1123
- template[RUN_RULE] = value => runLazyRules(rules, value); // `test` returns a boolean
1124
-
1125
-
1126
- template[TEST_RULE] = value => runLazyRules(rules, EnforceContext.wrap(value).setFailFast(true)).pass;
1127
-
1128
- return template;
1129
- });
1130
- }
1131
-
1132
- const Enforce = value => {
1133
- const proxy = genRuleProxy({}, ruleName => withArgs(args => {
1134
- runner(runtimeRules[ruleName], value, args);
1135
- return proxy;
1136
- }));
1137
- return proxy;
1138
- };
1139
-
1140
- const enforce = genRuleProxy(Enforce, bindLazyRule);
1141
- bindExtend(enforce, Enforce);
1142
- bindTemplate(enforce);
1143
-
1144
- module.exports = enforce;