",
19 | "license": "BSD-3-Clause",
20 | "bugs": {
21 | "url": "https://github.com/rsamec/business-rules-engine/issues"
22 | },
23 | "dependencies": {
24 | "q": "1.0.1",
25 | "axios": "^0.3.1",
26 | "hashmap": "^1.1.0",
27 | "moment": "2.5.0",
28 | "underscore": "^1.0.6",
29 | "underscore.string": "^2.3.3"
30 | },
31 | "devDependencies": {
32 | "expect.js": "~0.2.0",
33 | "grunt": "~0.4.1",
34 | "grunt-cli": "~0.1.9",
35 | "grunt-complexity": "~0.1.3",
36 | "grunt-contrib-commands": "^0.1.6",
37 | "grunt-contrib-concat": "^0.5.0",
38 | "grunt-contrib-copy": "^0.5.0",
39 | "grunt-contrib-jshint": "~0.6.4",
40 | "grunt-contrib-uglify": "^0.5.1",
41 | "grunt-contrib-watch": "~0.5.3",
42 | "grunt-docular": "^0.1.2",
43 | "grunt-mocha-cli": "^1.9.0",
44 | "grunt-ngdocs": "^0.2.2",
45 | "grunt-run": "^0.2.3",
46 | "grunt-typedoc": "^0.1.1",
47 | "grunt-typescript": "^0.3.8",
48 | "sinon": "^1.12.1",
49 | "typedoc": "^0.1.1"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/customValidators/DateCompareValidator.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | import moment = require("moment");
5 | import _ = require("underscore");
6 |
7 |
8 | /**
9 | * @ngdoc object
10 | * @name DateCompareValidator
11 | *
12 | * @requires moment
13 | * @requires underscore
14 | *
15 | * @description
16 | * DateCompareValidator enables to compare date to another date (CompareTo).
17 | *
18 | * @property CompareTo
19 | * The datetime against the compare is done.
20 | * If property is not set, then comparison is done against actual datetime.
21 | *
22 | * @property IgnoreDate
23 | * It forces to ignore time part of date by date compare.
24 | *
25 | *
26 | * @example
27 | * ```typescript
28 | *
29 | * //create validator
30 | * var validator = new dateCompareValidator();
31 | * validator.CompareTo = new Date(2000,2,2);
32 | * validator.CompareOperator = Validation.CompareOperator.LessThanEqual;
33 | *
34 | *
35 | * //less more than month -> return true
36 | * var result = validator.isAcceptable(new Date(2000,1,1));
37 | * //equal up to days -> return true
38 | * var result = validator.isAcceptable(new Date(2000,2,2));
39 | *
40 | * ```
41 | *
42 | */
43 |
44 | class DateCompareValidator implements Validation.IPropertyValidator{
45 |
46 | public isAcceptable(s:any){
47 | var isValid = false;
48 |
49 | //if date to compare is not specified - defaults to compare against now
50 | if (!_.isDate(s)) return false;
51 |
52 | if (this.CompareTo === undefined) Date.now();
53 |
54 | var now = moment(this.CompareTo);
55 | var then = moment(s);
56 |
57 | var diffs:number = then.diff(now);
58 | if (this.IgnoreTime) diffs = moment.duration(diffs).days();
59 |
60 | if (diffs < 0) {
61 | isValid = this.CompareOperator === Validation.CompareOperator.LessThan
62 | || this.CompareOperator === Validation.CompareOperator.LessThanEqual
63 | || this.CompareOperator === Validation.CompareOperator.NotEqual;
64 | }
65 | else if (diffs > 0) {
66 | isValid = this.CompareOperator === Validation.CompareOperator.GreaterThan
67 | || this.CompareOperator === Validation.CompareOperator.GreaterThanEqual
68 | || this.CompareOperator === Validation.CompareOperator.NotEqual;
69 | }
70 | else {
71 | isValid = this.CompareOperator === Validation.CompareOperator.LessThanEqual
72 | || this.CompareOperator === Validation.CompareOperator.Equal
73 | || this.CompareOperator === Validation.CompareOperator.GreaterThanEqual;
74 | }
75 | return isValid;
76 | }
77 |
78 | /**
79 | * Set the time of compare between passed date and CompareTo date.
80 | */
81 | public CompareOperator:Validation.CompareOperator;
82 |
83 | /**
84 | * The datetime against the compare is done.
85 | * If CompareTo is not set, then comparison is done against actual datetime.
86 | */
87 | public CompareTo:Date;
88 |
89 | /**
90 | * It forces to ignore time part of date by date compare.
91 | */
92 | public IgnoreTime:boolean = false;
93 |
94 | tagName = 'dateCompare';
95 |
96 | // public getErrorMessage(localMessages:any) {
97 | // var msg = '';
98 | // var messages = localMessages[this.tagName];
99 | //
100 | // var format:string = messages["Format"];
101 | // if (format != undefined) {
102 | // _.extend(this, {FormatedCompareTo: moment(this.CompareTo).format(format)})
103 | // }
104 | //
105 | // switch (this.CompareOperator) {
106 | // case Validation.CompareOperator.LessThan:
107 | // msg = messages["LessThan"];
108 | // break;
109 | // case Validation.CompareOperator.LessThanEqual:
110 | // msg = messages["LessThanEqual"];
111 | // break;
112 | // case Validation.CompareOperator.Equal:
113 | // msg = messages["Equal"];
114 | // break;
115 | // case Validation.CompareOperator.NotEqual:
116 | // msg = messages["NotEqual"];
117 | // break;
118 | // case Validation.CompareOperator.GreaterThanEqual:
119 | // msg = messages["GreaterThanEqual"];
120 | // break;
121 | // case Validation.CompareOperator.GreaterThan:
122 | // msg = messages["GreaterThan"];
123 | // break;
124 | // }
125 | // return DateCompareValidator.format(msg.replace('CompareTo','FormatedCompareTo'),this);
126 | // }
127 | // tagName = 'dateCompare';
128 | //
129 | // static format(s: string, args: any): string {
130 | // var formatted = s;
131 | // for (var prop in args) {
132 | // var regexp = new RegExp('\\{' + prop + '\\}', 'gi');
133 | // formatted = formatted.replace(regexp, args[prop]);
134 | // }
135 | // return formatted;
136 | // }
137 | }
138 |
139 | export = DateCompareValidator;
140 |
--------------------------------------------------------------------------------
/src/customValidators/ICOValidator.ts:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * @ngdoc object
4 | * @name ICOValidator
5 | *
6 | * @description
7 | * Return true for valid identification number of CZE company (called ico), otherwise return false.
8 | *
9 | * @example
10 | *
11 | *
12 | * //create validator
13 | * var validator = new IcoValidator();
14 | *
15 | * //valid IC -> return true
16 | * var result = validator.isAcceptable('12312312');
17 | * //unvalid IC -> return true
18 | * var result = validator.isAcceptable('11111111');
19 | *
20 | *
21 | */
22 | class ICOValidator {
23 |
24 | /**
25 | * It checks validity of identification number of CZE company (called ico)
26 | * @param input {string} value to check
27 | * @returns {boolean} return true for valid value, otherwise false
28 | */
29 | public isAcceptable(input: string) {
30 |
31 | if (input === undefined) return false;
32 | if (input.length === 0) return false;
33 |
34 | if (!/^\d+$/.test(input)) return false;
35 |
36 | var Sci = [];
37 | var Souc;
38 | var Del = input.length;
39 | var kon = parseInt(input.substring(Del, Del - 1), 10);// CLng(Right(strInput, 1));
40 | //var Numer = parseInt(input.substring(0,Del - 1),10);
41 | Del = Del - 1;
42 | Souc = 0;
43 | for (var a = 0; a < Del; a++) {
44 | Sci[a] = parseInt(input.substr((Del - a) - 1, 1), 10);
45 | Sci[a] = Sci[a] * (a + 2);
46 | Souc = Souc + Sci[a];
47 | }
48 |
49 | if (Souc > 0) {
50 | //var resul = 11 - (Souc % 11);
51 | var resul = Souc % 11;
52 | var mezi = Souc - resul;
53 | resul = mezi + 11;
54 | resul = resul - Souc;
55 |
56 | if ((resul === 10 && kon === 0) || (resul === 11 && kon === 1) || (resul === kon))
57 | return true;
58 | }
59 | return false;
60 | }
61 |
62 | tagName = "ico";
63 | }
64 |
65 | export = ICOValidator;
--------------------------------------------------------------------------------
/src/customValidators/ParamValidator.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 |
5 |
6 | import Q = require("q");
7 | import _ = require("underscore");
8 |
9 | /**
10 | * @ngdoc object
11 | * @name ParamValidator
12 | *
13 | * @requires Q
14 | *
15 | * @description
16 | * Returns true if the value is present in the list. Otherwise return false.
17 | * The list is returned via Options property that can be parametrize by the name of the list with ParamId parameter.
18 | *
19 | * @property Options
20 | * Promise that returns list of param items (key-value pairs)
21 | *
22 | *
23 | * var optionsFce = function (paramId:string) {
24 | * var deferral = Q.defer();
25 | * setTimeout(function () {
26 | * var result:Array = [];
27 | * if (paramId == "jobs") {
28 | * result = [
29 | * { "value": 1, "text": "manager" },
30 | * { "value": 2, "text": "programmer" },
31 | * { "value": 3, "text": "shop assistant" },
32 | * { "value": 4, "text": "unemployed" },
33 | * { "value": 5, "text": "machinery" },
34 | * { "value": 6, "text": "agriculture" },
35 | * { "value": 7, "text": "academic" },
36 | * { "value": 8, "text": "goverment" }
37 | * ];
38 | * }
39 | * if (paramId == "countries") {
40 | * result = [
41 | * { "value": "CZE", "text": "Czech Republic" },
42 | * { "value": "Germany", "text": "Germany" },
43 | * { "value": "France", "text": "France" },
44 | * ];
45 | * }
46 | *
47 | *
48 | * deferral.resolve(result);
49 | * }, 1000);
50 | * return deferral.promise;
51 | * };
52 | *
53 | *
54 | * @property ParamId - The name of the list to be returned.
55 | *
56 | * @example
57 | *
58 | *
59 | * //when
60 | * var validator = new paramValidator();
61 | * validator.Options = optionsFce;
62 | * validator.ParamId = "jobs";
63 | *
64 | * //excercise
65 | * var promiseResult = validator.isAcceptable("programmer");
66 | *
67 | * it('value from list should return true', function (done) {
68 | *
69 | * promiseResult.then(function(result) {
70 | *
71 | * //verify
72 | * expect(result).to.equal(true);
73 | *
74 | * done();
75 | *
76 | * }).done(null, done);
77 | * });
78 | *
79 | * //excercise
80 | * var promiseResult2 = validator.isAcceptable("non existing item");
81 | *
82 | * it('value out of list should return false', function (done) {
83 | *
84 | * promiseResult2.then(function(result) {
85 | *
86 | * //verify
87 | * expect(result).to.equal(false);
88 | *
89 | * done();
90 | *
91 | * }).done(null, done);
92 | * });
93 | *
94 | *
95 | */
96 | class ParamValidator implements Validation.IAsyncPropertyValidator{
97 |
98 | /**
99 | * It checks validity of identification number of CZE company (called ico)
100 | * @param s value to check
101 | * @returns return true for valid value, otherwise false
102 | */
103 | isAcceptable(s:string):Q.Promise {
104 | var deferred = Q.defer();
105 |
106 | this.Options(this.ParamId).then(function (result) {
107 | var hasSome = _.some(result, function (item) {
108 | return item.text === s;
109 | });
110 | if (hasSome) deferred.resolve(true);
111 | deferred.resolve(false);
112 | });
113 |
114 | return deferred.promise;
115 | }
116 |
117 | public ParamId:string;
118 | public Options:{(string): Q.Promise>};
119 |
120 | isAsync = true;
121 | tagName = "param";
122 | }
123 | export = ParamValidator;
--------------------------------------------------------------------------------
/src/customValidators/RCValidator.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 |
5 | import moment = require("moment");
6 | import _s= require("underscore.string");
7 |
8 | /**
9 | * @ngdoc object
10 | * @name RCValidator
11 | *
12 | * @requires moment
13 | * @requires underscore.string
14 | *
15 | * @description
16 | * Return true for valid birth day number in Czech Republic, otherwise return false.
17 | *
18 | * @example
19 | *
20 | *
21 | *
22 | * //create validator
23 | * var validator = new RCValidator();
24 | *
25 | * //valid RC -> return true
26 | * var result = validator.isAcceptable('800101/9999');
27 | * //unvalid RC -> return false
28 | * var result = validator.isAcceptable('111111/1752');
29 | *
30 | *
31 | */
32 | class RCValidator implements Validation.IPropertyValidator {
33 |
34 | public tagName:string = 'rc';
35 |
36 | public isAcceptable(s:any):boolean {
37 |
38 | var old:boolean = false;
39 | var month:number;
40 | var year:number;
41 | var day:number;
42 | var numrc:any;
43 | var dbg = false;
44 | if (s === undefined) return false;
45 | if (s.toString().length === 0) {
46 | return false;
47 | }
48 |
49 | if (!s.match(/^\d{6}\/?\d{3,4}$/)) return false;
50 |
51 | if (s.indexOf('/') != -1)
52 | old = s.length === 10;
53 | else
54 | old = s.length === 9;
55 |
56 | if (s.indexOf('/') !== -1) {
57 | numrc = s.split("/");
58 | numrc = numrc.join("");
59 | } else {
60 | numrc = s
61 | }
62 |
63 | day = parseInt(numrc.substring(4, 6), 10);
64 | month = parseInt(numrc.substring(2, 4), 10);
65 | year = parseInt(numrc.substring(0, 2), 10);
66 |
67 | if (s.match(/\/?(0000?|8888?|9999?)$/)) {
68 | dbg = true;
69 | }
70 |
71 | if (!old && !dbg) {
72 | if (numrc % 11 !== 0 && s.substr(s.length - 1) === "0") {
73 | if (parseInt(numrc.substr(0, 9), 10) % 11 !== 10) return false;
74 | }
75 | else if (numrc % 11 !== 0) return false;
76 | }
77 |
78 | if (year > 54 && old && !dbg) return false;
79 |
80 | if (!old && year < 54) year = 2000 + year;
81 | else year = 1900 + year;
82 |
83 | if (month > 50 && month < 63) month = month - 50;
84 | if (!old && year >= 2004) { //vyjimka na pricitani dvojek k mesici
85 | if (month > 20 && month < 33) month = month - 20;
86 | if (month > 70 && month < 83) month = month - 70;
87 | }
88 |
89 | var datum = moment(_s.lpad(day.toString(), 2, '0') + "." + _s.lpad(month.toString(), 2, '0') + "." + year, "DD.MM.YYYY");
90 |
91 | if (!datum.isValid()) return false;
92 | return datum.toDate() <= moment(Date.now()).toDate();
93 |
94 | }
95 | }
96 |
97 | export = RCValidator;
--------------------------------------------------------------------------------
/src/localization/messages_cz.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": "Tento údaj je povinný.",
3 | "remote": "Prosím, opravte tento údaj.",
4 | "email": "Prosím, zadejte platný e-mail.",
5 | "url": "Prosím, zadejte platné URL.",
6 | "date": "Prosím, zadejte platné datum.",
7 | "dateISO": "Prosím, zadejte platné datum (ISO).",
8 | "number": "Prosím, zadejte číslo.",
9 | "digits": "Prosím, zadávejte pouze číslice.",
10 | "creditcard": "Prosím, zadejte číslo kreditní karty.",
11 | "equalTo": "Prosím, zadejte znovu stejnou hodnotu.",
12 | "extension": "Prosím, zadejte soubor se správnou příponou.",
13 | "maxlength": "Prosím, zadejte nejvíce {MaxLength} znaků.",
14 | "minlength": "Prosím, zadejte nejméně {MinLength} znaků.",
15 | "rangelength": "Prosím, zadejte od {MinLength} do {MaxLength} znaků.",
16 | "range": "Prosím, zadejte hodnotu od {Min} do {Max}.",
17 | "max": "Prosím, zadejte hodnotu menší nebo rovnu {Max}.",
18 | "min": "Prosím, zadejte hodnotu větší nebo rovnu {Min}.",
19 | "contains": "Prosím, zadejte hodnotu ze seznamu. Zadaná hodnota {AttemptedValue}.",
20 | "minItems": "Prosím zadejte alespoň {Min} položek.",
21 | "maxItems": "Prosím zadejte maximálně {Max} položek.",
22 | "uniqItems": "Prosím zadejte pouze unikátní hodnoty.",
23 | "enum":"Prosím zadajte povolenou hodnotu.",
24 | "type":"Prosím zadejte hodnotu typu '{Type}'.",
25 | "multipleOf":"Prosím zadejte hodnotu dělitelnou číslem '{Divider}'."
26 | }
--------------------------------------------------------------------------------
/src/localization/messages_cz.ts:
--------------------------------------------------------------------------------
1 | class Localization {
2 |
3 | /*
4 | * Translated default messages for the validation engine.
5 | * Locale: CS (Czech; čeština, český jazyk)
6 | */
7 | static get ValidationMessages():any {
8 | return {
9 | required: "Tento údaj je povinný.",
10 | remote: "Prosím, opravte tento údaj.",
11 | email: "Prosím, zadejte platný e-mail.",
12 | url: "Prosím, zadejte platné URL.",
13 | date: "Prosím, zadejte platné datum.",
14 | dateISO: "Prosím, zadejte platné datum (ISO).",
15 | number: "Prosím, zadejte číslo.",
16 | digits: "Prosím, zadávejte pouze číslice.",
17 | creditcard: "Prosím, zadejte číslo kreditní karty.",
18 | equalTo: "Prosím, zadejte znovu stejnou hodnotu.",
19 | extension: "Prosím, zadejte soubor se správnou příponou.",
20 | maxlength: "Prosím, zadejte nejvíce {MaxLength} znaků.",
21 | minlength: "Prosím, zadejte nejméně {MinLength} znaků.",
22 | rangelength: "Prosím, zadejte od {MinLength} do {MaxLength} znaků.",
23 | range: "Prosím, zadejte hodnotu od {Min} do {Max}.",
24 | max: "Prosím, zadejte hodnotu menší nebo rovnu {Max}.",
25 | min: "Prosím, zadejte hodnotu větší nebo rovnu {Min}.",
26 | contains: "Prosím, zadejte hodnotu ze seznamu. Zadaná hodnota {AttemptedValue}.",
27 | dateCompare: {
28 | Format: "DD.MM.YYYY",
29 | LessThan: "Prosím, zadejte datum menší než {CompareTo}.",
30 | LessThanEqual: "Prosím, zadejte datum menší nebo rovné {CompareTo}.",
31 | Equal: "Prosím, zadejte {CompareTo}.",
32 | NotEqual: "Prosím, zadejte datum různé od {CompareTo}.",
33 | GreaterThanEqual: "Prosím, zadejte datum větší nebo rovné {CompareTo}.",
34 | GreaterThan: "Prosím, zadejte datum větší než {CompareTo}."
35 | },
36 | minItems:"Prosím zadejte alespoň {Min} položek.",
37 | maxItems:"Prosím zadejte maximálně {Max} položek.",
38 | uniqItems:"Prosím zadejte pouze unikátní hodnoty.",
39 | enum:"Prosím zadajte povolenou hodnotu.",
40 | type:"Prosím zadejte hodnotu typu '{Type}'.",
41 | multipleOf:"Prosím zadejte hodnotu dělitelnou číslem '{Divider}'."
42 | };
43 | }
44 | }
45 |
46 | export = Localization;
47 |
--------------------------------------------------------------------------------
/src/localization/messages_de.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": "Dieses Feld ist ein Pflichtfeld.",
3 | "maxlength": "Geben Sie bitte maximal {MaxLength} Zeichen ein.",
4 | "minlength": "Geben Sie bitte mindestens {MinLength} Zeichen ein.",
5 | "rangelength": "Geben Sie bitte mindestens {MinLength} und maximal {MaxLength} Zeichen ein.",
6 | "email": "Geben Sie bitte eine gültige E-Mail Adresse ein.",
7 | "url": "Geben Sie bitte eine gültige URL ein.",
8 | "date": "Bitte geben Sie ein gültiges Datum ein.",
9 | "number": "Geben Sie bitte eine Nummer ein.",
10 | "digits": "Geben Sie bitte nur Ziffern ein.",
11 | "equalTo": "Bitte denselben Wert wiederholen.",
12 | "range": "Geben Sie bitte einen Wert zwischen {Min} und {Max} ein.",
13 | "max": "Geben Sie bitte einen Wert kleiner oder gleich {Max} ein.",
14 | "min": "Geben Sie bitte einen Wert größer oder gleich {Min} ein.",
15 | "creditcard": "Geben Sie bitte eine gültige Kreditkarten-Nummer ein.",
16 | "minItems": "Geben Sie bitte minimal {Min} Einträge.",
17 | "maxItems": "Geben Sie bitte maximal {Max} Einträge.",
18 | "uniqItems": "Geben Sie bitte maximal unique Einträge.",
19 | "enum": "Geben Sie bitte einen Wert.",
20 | "type": "Geben Sie bitte einen Wert von '{Type}'.",
21 | "multipleOf": "Geben Sie bitte einen Wert als multiple of {Divider}."
22 | }
--------------------------------------------------------------------------------
/src/localization/messages_de.ts:
--------------------------------------------------------------------------------
1 | class Localization {
2 |
3 | /*
4 | * Translated default messages for the validation engine.
5 | * Locale: DE (German, Deutsch)
6 | */
7 | static get ValidationMessages():any {
8 | return {
9 | required: "Dieses Feld ist ein Pflichtfeld.",
10 | maxlength: "Geben Sie bitte maximal {MaxLength} Zeichen ein.",
11 | minlength: "Geben Sie bitte mindestens {MinLength} Zeichen ein.",
12 | rangelength: "Geben Sie bitte mindestens {MinLength} und maximal {MaxLength} Zeichen ein.",
13 | email: "Geben Sie bitte eine gültige E-Mail Adresse ein.",
14 | url: "Geben Sie bitte eine gültige URL ein.",
15 | date: "Bitte geben Sie ein gültiges Datum ein.",
16 | number: "Geben Sie bitte eine Nummer ein.",
17 | digits: "Geben Sie bitte nur Ziffern ein.",
18 | equalTo: "Bitte denselben Wert wiederholen.",
19 | range: "Geben Sie bitte einen Wert zwischen {Min} und {Max} ein.",
20 | max: "Geben Sie bitte einen Wert kleiner oder gleich {Max} ein.",
21 | min: "Geben Sie bitte einen Wert größer oder gleich {Min} ein.",
22 | creditcard: "Geben Sie bitte eine gültige Kreditkarten-Nummer ein.",
23 | dateCompare: {
24 | LessThan: "Geben Sie bitte ein datum kleiner {CompareTo}.",
25 | LessThanEqual: "Geben Sie bitte ein datum kleiner oder gleich {CompareTo}.",
26 | Equal: "Geben Sie bitte ein datum {CompareTo}.",
27 | NotEqual: "Geben Sie bitte ein datum anderes von {CompareTo}.",
28 | GreaterThanEqual: "Geben Sie bitte ein datum größer oder gleich {CompareTo}.",
29 | GreaterThan: "Geben Sie bitte ein datum größer {CompareTo}."
30 | },
31 | minItems:"Geben Sie bitte minimal {Min} Einträge.",
32 | maxItems:"Geben Sie bitte maximal {Max} Einträge.",
33 | uniqItems:"Geben Sie bitte maximal unique Einträge.",
34 | enum:"Geben Sie bitte einen Wert.",
35 | type:"Geben Sie bitte einen Wert von '{Type}'.",
36 | multipleOf:"Geben Sie bitte einen Wert als multiple of {Divider}."
37 | }
38 | }
39 | }
40 |
41 | export = Localization;
--------------------------------------------------------------------------------
/src/localization/messages_en.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": "This field is required.",
3 | "remote": "Please fix the field.",
4 | "email": "Please enter a valid email address.",
5 | "url": "Please enter a valid URL.",
6 | "date": "Please enter a valid date.",
7 | "dateISO": "Please enter a valid date ( ISO ).",
8 | "number": "Please enter a valid number.",
9 | "digits": "Please enter only digits.",
10 | "signedDigits": "Please enter only signed digits.",
11 | "creditcard": "Please enter a valid credit card number.",
12 | "equalTo": "Please enter the same value again.",
13 | "maxlength": "Please enter no more than {MaxLength} characters.",
14 | "minlength": "Please enter at least {MinLength} characters.",
15 | "rangelength": "Please enter a value between {MinLength} and {MaxLength} characters long.",
16 | "range": "Please enter a value between {Min} and {Max}.",
17 | "max": "Please enter a value less than or equal to {Max}.",
18 | "min": "Please enter a value greater than or equal to {Min}.",
19 | "step": "Please enter a value with step {Step}.",
20 | "contains": "Please enter a value from list of values. Attempted value '{AttemptedValue}'.",
21 | "mask": "Please enter a value corresponding with {Mask}.",
22 | "minItems":"Please enter at least {Min} items.",
23 | "maxItems":"Please enter at least {Max} items.",
24 | "uniqItems":"Please enter unique items.",
25 | "enum":"Please enter a value from list of permitted values.",
26 | "type":"Please enter a value of type '{Type}'.",
27 | "multipleOf":"Please enter a value that is multiple of {Divider}."
28 | }
--------------------------------------------------------------------------------
/src/localization/messages_en.ts:
--------------------------------------------------------------------------------
1 |
2 | class Localization {
3 |
4 | /*
5 | * Translated default messages for the validation engine.
6 | * Locale: EN (English; english)
7 | */
8 | static get ValidationMessages():any {
9 | return {
10 | required: "This field is required.",
11 | remote: "Please fix the field.",
12 | email: "Please enter a valid email address.",
13 | url: "Please enter a valid URL.",
14 | date: "Please enter a valid date.",
15 | dateISO: "Please enter a valid date ( ISO ).",
16 | number: "Please enter a valid number.",
17 | digits: "Please enter only digits.",
18 | signedDigits: "Please enter only signed digits.",
19 | creditcard: "Please enter a valid credit card number.",
20 | equalTo: "Please enter the same value again.",
21 | maxlength: "Please enter no more than {MaxLength} characters.",
22 | minlength: "Please enter at least {MinLength} characters.",
23 | rangelength: "Please enter a value between {MinLength} and {MaxLength} characters long.",
24 | range: "Please enter a value between {Min} and {Max}.",
25 | max: "Please enter a value less than or equal to {Max}.",
26 | min: "Please enter a value greater than or equal to {Min}.",
27 | step: "Please enter a value with step {Step}.",
28 | contains: "Please enter a value from list of values. Attempted value '{AttemptedValue}'.",
29 | mask: "Please enter a value corresponding with {Mask}.",
30 | dateCompare: {
31 | Format: "MM/DD/YYYY",
32 | LessThan: "Please enter date less than {CompareTo}.",
33 | LessThanEqual: "Please enter date less than or equal {CompareTo}.",
34 | Equal: "Please enter date equal {CompareTo}.",
35 | NotEqual: "Please enter date different than {CompareTo}.",
36 | GreaterThanEqual: "Please enter date greater than or equal {CompareTo}.",
37 | GreaterThan: "Please enter date greter than {CompareTo}."
38 | },
39 | minItems:"Please enter at least {Min} items.",
40 | maxItems:"Please enter no more than {Max} items.",
41 | uniqItems:"Please enter unique items.",
42 | enum:"Please enter a value from list of permitted values.",
43 | type:"Please enter a value of type '{Type}'.",
44 | multipleOf:"Please enter a value that is multiple of {Divider}."
45 | }
46 | }
47 | }
48 |
49 | export = Localization;
50 |
--------------------------------------------------------------------------------
/src/metaDataRules/form.ts:
--------------------------------------------------------------------------------
1 | /////
2 | /////
3 | //
4 | /////
5 | /////
6 | //
7 | //
8 | //module Validation {
9 | //
10 | // export interface IForm {
11 | // Errors:IValidationResult;
12 | // //Validators:Validators;
13 | //
14 | // Validate():void;
15 | // }
16 | //
17 | // /**
18 | // * YUIDoc_comment
19 | // *
20 | // * @class form
21 | // * @constructor
22 | // **/
23 | // export class MetaForm implements IForm{
24 | //
25 | // public CLASS_NAME:string = 'form';
26 | //
27 | // public Errors:IValidationResult = new CompositeValidationResult("Main form");
28 | // //public Validators:Validators = new Validators();
29 | //
30 | // public MetaRules:MetaDataRules;
31 | //
32 | //
33 | // constructor(public MetaData:any) {
34 | // this.Data = {};
35 | // Util.generateDataEx(this.MetaData,this.Data);
36 | //
37 | // this.MetaRules = new MetaDataRules(this.Data,this.MetaData);
38 | //
39 | // _.each(this.MetaRules.Rules, function(rule:MetaDataRule) {
40 | // this.Errors.Add(rule.Error);
41 | // },this);
42 | // }
43 | //
44 | // public Data:any;
45 | //
46 | // public Validate():void
47 | // {
48 | // this.MetaRules.ValidateAll();
49 | // //this.Validators.ValidateAll();
50 | // }
51 | // }
52 | //}
53 | ////var _ = require('underscore');
54 | ////var Q = require('q');
55 | ////exports.Validation = Validation
--------------------------------------------------------------------------------
/src/metaDataRules/metaDataRules.ts:
--------------------------------------------------------------------------------
1 | /////
2 | /////
3 | /////
4 | //
5 | ////import Validators = require("../customValidators/BasicValidators.js");
6 | //
7 | //module Validation {
8 | //
9 | //*
10 | // * This represents validation rule.
11 | //
12 | //
13 | // export interface IMetaRule {
14 | // Method: string;
15 | // Parameters?: any;
16 | // }
17 | //
18 | //*
19 | // * YUIDoc_comment
20 | // *
21 | //
22 | // export class MetaDataRules {
23 | //
24 | // public CLASS_NAME:string = 'MetaDataRules';
25 | //
26 | // public Rules: { [index: string]: MetaDataRule; } = {};
27 | //
28 | // constructor(public Data:any, public MetaData:any) {
29 | // for (var key in this.MetaData) {
30 | // var metaData = this.MetaData[key];
31 | // if (metaData[Util.RULE_PROPERTY_NAME] !== undefined) {
32 | // this.Rules[key] = new MetaDataRule(metaData,new ValidationContext(key,this.Data))
33 | // }
34 | // }
35 | // }
36 | //
37 | // public ValidateAll():void {
38 | // for (var key in this.Rules)
39 | // {
40 | // this.Rules[key].Validate();
41 | // }
42 | // }
43 | // }
44 | //
45 | //*
46 | // * Defines a rule associated with a property which can have multiple validators
47 | //
48 | //
49 | // export class MetaDataRule{
50 | //
51 | // public Rule: PropertyValidationRule;
52 | //
53 | // public get MetaErrors() { return this.Rule.ValidationFailures;}
54 | //
55 | // public get Error():IValidationResult {return this.Rule;}
56 | //
57 | // constructor(metaData: any, public Context:IValidationContext) {
58 | //
59 | // //read label from metadata
60 | // var label = metaData[Util.LABEL_PROPERTY_NAME];
61 | // var name = label !== undefined ? label : this.Context.Key;
62 | //
63 | // var validators:Array = [];
64 | // for (var method in metaData.rules) {
65 | // //create validators
66 | // var validator = this.CreateValidator({Method: method, Parameters: metaData.rules[method]});
67 | // validators.push(validator);
68 | // }
69 | //
70 | // this.Rule = new PropertyValidationRule(name,validators);
71 | //
72 | //
73 | //
74 | // //this.Error.Optional = this.Context.Optional;
75 | //
76 | // }
77 | //
78 | // private CreateValidator(rule:IMetaRule):IPropertyValidator{
79 | //
80 | //// switch (rule.Method) {
81 | //// case "required":
82 | //// return new Validators.RequiredValidator();
83 | ////
84 | ////
85 | ////
86 | //// case "minlength":
87 | //// var validator = new Validators.MinLengthValidator();
88 | //// validator.MinLength = rule.Parameters;
89 | //// return validator;
90 | //// case "maxlength":
91 | //// var maxLengthValidator = new Validators.MaxLengthValidator();
92 | //// maxLengthValidator.MaxLength = rule.Parameters;
93 | //// return maxLengthValidator;
94 | //// }
95 | // return undefined;
96 | // }
97 | //
98 | // public Validate(): void {
99 | // this.Rule.Validate(this.Context);
100 | // }
101 | // public ClearErrors(): void{
102 | // for (var key in this.MetaErrors) {
103 | // var target = this.MetaErrors[key];
104 | // target.Error.ErrorMessage = "";
105 | // target.Error.HasError = false;
106 | // }
107 | // }
108 | // }
109 | //
110 | //*
111 | // * It represents composition of error objects for rules defined with meta data.
112 | //
113 | //
114 | // export class MetaRulesValidationResult extends CompositeValidationResult implements IValidationResult {
115 | //
116 | // constructor(public Name: string,public MetaRules:any) {
117 | //
118 | // super(Name);
119 | //
120 | // _.each(this.MetaRules.Rules, function(rule:any) {
121 | // this.Add(rule.Error);
122 | // },this);
123 | // }
124 | //
125 | // }
126 | //}
127 |
--------------------------------------------------------------------------------
/src/metaDataRules/util.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | module Validation {
4 |
5 | /**
6 | * YUIDoc_comment
7 | *
8 | * @class util
9 | * @constructor
10 | **/
11 | export class Util {
12 |
13 | public CLASS_NAME:string = 'util';
14 |
15 | static RULE_PROPERTY_NAME:string = "rules";
16 | static LABEL_PROPERTY_NAME:string = "label";
17 |
18 | constructor() {
19 |
20 | }
21 |
22 | static generateData(metaData:any){
23 | var data = {}
24 | Util.generateDataEx(metaData,data);
25 | return data;
26 | }
27 |
28 | //TODO: find better way how to distinguish between data fields items and meta data information
29 | //TODO: better documentation
30 | static generateDataEx(o, data, parentPath?){
31 | //TODO: better implementation - like _.defaults()
32 | var metaDataKeys = ["label", "rules", "help", "id", "defaultValue", "options","unit","hint", "Common", "disclaimer","saveOptions","optionsRef","apiId"];
33 | var tableKey = "RowData";
34 |
35 | var containsLeafFce = function (key) { return _.contains(this, key) };
36 | var containsTableFce = function (key) {return key == this };
37 | for (var key in o) {
38 | if (_.contains(metaDataKeys, key)) continue;
39 | var item = o[key];
40 |
41 | if (_.isArray(item)) {
42 | data[key] = item;
43 | continue;
44 | }
45 | if (typeof (item) == "object") {
46 | var isLeafNode = _.every(_.keys(item), containsLeafFce, metaDataKeys);
47 | if (isLeafNode) {
48 | data[key] = undefined;
49 | continue;
50 | }
51 | var isTableNode = _.some(_.keys(item),containsTableFce,tableKey);
52 | if (isTableNode) {
53 | data[key] = [];
54 | continue;
55 | }
56 |
57 |
58 | data[key] = {};
59 | var path = parentPath === undefined ? key : parentPath + "." + key;
60 | //going on step down in the object tree!!
61 | this.generateDataEx(o[key], data[key], path);
62 | }
63 | }
64 | }
65 |
66 | }
67 | }
--------------------------------------------------------------------------------
/src/validation/Utils.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | import _ = require('underscore');
5 | /**
6 | * Utility functions for business rules purposes.
7 | *
8 | * + String functions
9 | * + Number functions
10 | */
11 | module Utils {
12 |
13 | /*
14 | It represents utility for string manipulation.
15 | */
16 | export class StringFce {
17 | static format(s:string, args:any):string {
18 | var formatted = s;
19 | for (var prop in args) {
20 | var regexp = new RegExp('\\{' + prop + '\\}', 'gi');
21 | formatted = formatted.replace(regexp, args[prop]);
22 | }
23 | return formatted;
24 | }
25 | }
26 |
27 | /*
28 | It represents utility for number manipulation.
29 | */
30 | export class NumberFce {
31 | static GetNegDigits(value:string):number {
32 | if (value === undefined) return 0;
33 | var digits = value.toString().split('.');
34 | if (digits.length > 1) {
35 | var negDigitsLength = digits[1].length;
36 | return negDigitsLength;
37 | }
38 | return 0;
39 | }
40 | }
41 |
42 | /*
43 | It represents signal (event).
44 | */
45 | export interface ISignal {
46 | add(listener: (parameter: T) => any, priority?: number): void;
47 | remove(listener: (parameter: T) => any): void;
48 | dispatch(parameter: T): boolean;
49 | clear(): void;
50 | hasListeners(): boolean;
51 | }
52 |
53 | /*
54 | It represents signal (event).
55 | */
56 | export class Signal implements ISignal {
57 | private listeners: { (parameter: T): any }[] = [];
58 | private priorities: number[] = [];
59 |
60 | add(listener: (parameter: T) => any, priority = 0): void {
61 | var index = this.listeners.indexOf(listener);
62 | if (index !== -1) {
63 | this.priorities[index] = priority;
64 | return;
65 | }
66 | for (var i = 0, l = this.priorities.length; i < l; i++) {
67 | if (this.priorities[i] < priority) {
68 | this.priorities.splice(i, 0, priority);
69 | this.listeners.splice(i, 0, listener);
70 | return;
71 | }
72 | }
73 | this.priorities.push(priority);
74 | this.listeners.push(listener);
75 | }
76 |
77 | remove(listener: (parameter: T) => any): void {
78 | var index = this.listeners.indexOf(listener);
79 | if (index >= 0) {
80 | this.priorities.splice(index, 1);
81 | this.listeners.splice(index, 1);
82 | }
83 | }
84 |
85 | dispatch(parameter: T): boolean {
86 | var indexesToRemove: number[];
87 | var hasBeenCanceled = this.listeners.every((listener: (parameter: T) => any) => {
88 | var result = listener(parameter);
89 | return result !== false;
90 | });
91 |
92 | return hasBeenCanceled;
93 | }
94 |
95 | clear(): void {
96 | this.listeners = [];
97 | this.priorities = [];
98 | }
99 |
100 | hasListeners(): boolean {
101 | return this.listeners.length > 0;
102 | }
103 | }
104 |
105 | /*
106 | It is component element from composite design pattern.
107 | */
108 | export interface IComponent{
109 | add(child:IComponent):boolean;
110 | remove(child:IComponent):boolean;
111 | getChildren():IComponent[];
112 | getName():string;
113 | isItem():boolean;
114 | }
115 |
116 | /*
117 | It represents utility for making composite object accessible by dot notation.
118 | */
119 | export class CompositeDotObject{
120 |
121 | /*
122 | It transforms composite object to dot accessible composite object.
123 | */
124 | static Transform(component:IComponent,obj){
125 | if (obj === undefined) obj = {};
126 | if (component.isItem()){
127 | obj[component.getName()] = component;
128 | }
129 | else{
130 | var children = component.getChildren();
131 | var parent = obj[component.getName()] = component;
132 | for (var comp in children ) {
133 | CompositeDotObject.Transform(children[comp],parent);
134 | }
135 | }
136 | return obj;
137 | }
138 | }
139 | }
140 | export = Utils;
--------------------------------------------------------------------------------
/test/customValidators/DataCompareValidator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by rsamec on 9.7.2014.
3 | */
4 | ///
5 | ///
6 | ///
7 |
8 | var expect = require('expect.js');
9 | import dateCompareValidator = require('../../src/customValidators/DateCompareValidator');
10 | import moment = require('moment')
11 |
12 | describe('DateCompareValidator', function () {
13 |
14 | describe("isAcceptable", function () {
15 | var params = [
16 | //less more than month
17 | { input: new Date(2000, 1, 1), result: true},
18 | //less more than day
19 | { input: new Date(2000, 2, 1), result: true},
20 | //equal up to days
21 | { input: new Date(2000, 2, 2), result: true },
22 | //equal up to miliseconds
23 | { input: new Date(2000, 2, 2, 0, 0, 0, 0), result: true },
24 | //greater about 1 milisecond
25 | { input: new Date(2000, 2, 2, 0, 0, 0, 1), result: false },
26 | //equal up to miliseconds
27 | { input: new Date(2000, 2, 2, 0, 0, 0, 0), result: true, ignoreTime: true },
28 | //greater about 1 milisecond
29 | { input: new Date(2000, 2, 2, 0, 0, 0, 1), result: true, ignoreTime: true },
30 | //greater about max hours
31 | { input: new Date(2000, 2, 2, 23, 59, 59, 99), result: true, ignoreTime: true },
32 | //greater about one day
33 | { input: new Date(2000, 2, 3, 0, 0, 0, 0), result: false, ignoreTime: true },
34 | //bad date
35 | { input: "", result: false },
36 | //bad date
37 | { input: undefined, result: false },
38 | //bad date
39 | { input: "{}", result: false },
40 | //bad date
41 | { input: "fasdfa", result: false }
42 | ];
43 |
44 | var validator = new dateCompareValidator();
45 | validator.CompareTo = new Date(2000, 2, 2);
46 | validator.CompareOperator = Validation.CompareOperator.LessThanEqual;
47 |
48 | for (var op in params) {
49 | (function (item) {
50 | it('should check date ' + item.input + ' is less then or equal -> ' + item.result, function () {
51 | if (item.ignoreTime !== undefined) validator.IgnoreTime = item.ignoreTime;
52 | expect(item.result).to.equal(validator.isAcceptable(item.input));
53 | });
54 | })(params[op]);
55 | }
56 |
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/customValidators/ICOValidator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by rsamec on 9.7.2014.
3 | */
4 | ///
5 | ///
6 | ///
7 |
8 | var expect = require('expect.js');
9 | import icoValidator = require('../../src/customValidators/ICOValidator');
10 |
11 | describe('ICOValidator', function () {
12 |
13 | var params = [
14 | { input: "70577200", result: true},
15 | { input: "3457890", result: false },
16 | { input: "7057720", result: false },
17 | { input: "45244782", result: true },
18 | { input: "25578898", result: true },
19 | { input: "61490041", result: true },
20 | { input: "11111111", result: false },
21 | { input: "12312312", result: true },
22 | { input: "", result: false },
23 | { input: undefined, result: false },
24 | { input: "{}", result: false },
25 | { input: "fasdfa", result: false }
26 | ];
27 | var validator = new icoValidator();
28 |
29 |
30 | for (var op in params) {
31 | (function (item) {
32 | it('should check ico number ' + item.input + ' -> ' + item.result, function () {
33 | expect(item.result).to.equal(validator.isAcceptable(item.input));
34 | });
35 | })(params[op]);
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/test/customValidators/ParamValidator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by rsamec on 9.7.2014.
3 | */
4 | ///
5 | ///
6 | ///
7 | ///
8 |
9 |
10 | var expect = require('expect.js');
11 | import paramValidator = require('../../src/customValidators/ParamValidator');
12 | var Q = require('q');
13 |
14 | describe('ParamValidator', function () {
15 |
16 | var optionsFce = function (paramId:string) {
17 | var deferral = Q.defer();
18 | setTimeout(function () {
19 | var result:Array = [];
20 | if (paramId == "jobs") {
21 | result = [
22 | { "value": 1, "text": "manager" },
23 | { "value": 2, "text": "programmer" },
24 | { "value": 3, "text": "shop assistant" },
25 | { "value": 4, "text": "unemployed" },
26 | { "value": 5, "text": "machinery" },
27 | { "value": 6, "text": "agriculture" },
28 | { "value": 7, "text": "academic" },
29 | { "value": 8, "text": "goverment" }
30 | ];
31 | }
32 | if (paramId == "countries") {
33 | result = [
34 | { "value": "CZE", "text": "Czech Republic" },
35 | { "value": "Germany", "text": "Germany" },
36 | { "value": "France", "text": "France" },
37 | ];
38 | }
39 |
40 |
41 | deferral.resolve(result);
42 | }, 1000);
43 | return deferral.promise;
44 | };
45 |
46 |
47 | //when
48 | var validator = new paramValidator();
49 | validator.Options = optionsFce;
50 | validator.ParamId = "jobs";
51 |
52 | //excercise
53 | var promiseResult = validator.isAcceptable("programmer");
54 |
55 | it('value from list should return true', function (done) {
56 |
57 | promiseResult.then(function(result) {
58 |
59 | //verify
60 | expect(result).to.equal(true);
61 |
62 | done();
63 |
64 | }).done(null, done);
65 | });
66 |
67 | //excercise
68 | var promiseResult2 = validator.isAcceptable("non existing item");
69 |
70 | it('value out of list should return false', function (done) {
71 |
72 | promiseResult2.then(function(result) {
73 |
74 | //verify
75 | expect(result).to.equal(false);
76 |
77 | done();
78 |
79 | }).done(null, done);
80 | });
81 |
82 | });
83 |
--------------------------------------------------------------------------------
/test/customValidators/RCValidator.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by rsamec on 9.7.2014.
3 | */
4 | ///
5 | ///
6 | ///
7 |
8 |
9 | var expect = require('expect.js');
10 | import rcValidator = require('../../src/customValidators/RCValidator');
11 |
12 | describe('RCValidator', function () {
13 |
14 | var validParams = ["062413/2256",
15 | "042111/2956",
16 | "043111/2957",
17 | "043211/2956",
18 | "045111/4411",
19 | "045211/4410",
20 | "045311/4409",
21 | "047111/3709",
22 | "047130/3712",
23 | "047131/3711",
24 | "047211/3411",
25 | "047311/3311",
26 | "047330/3314",
27 | "047331/3313",
28 | "047430/3313",
29 | "047831/3011",
30 | "440229/234",
31 | "441129/342",
32 | "800122/8763",
33 | "048111/3413",
34 | "048130/1810",
35 | "048231/1610",
36 | "071111/145",
37 | "071111/1610",
38 | "073211/1611",
39 | "076211/1614",
40 | "077111/1616",
41 | "078111/1716",
42 | "083111/2216",
43 | "430228/134",
44 | "431122/155",
45 | "431128/231",
46 | "431129/178",
47 | "431222/141",
48 | "431231/172",
49 | "436122/931",
50 | "436222/165",
51 | "010101/222"];
52 |
53 | var validator = new rcValidator();
54 |
55 | for (var op in validParams) {
56 | (function (item) {
57 | it('should check rc number ' + item + ' -> OK', function () {
58 | expect(validator.isAcceptable(item)).to.equal(true);
59 | });
60 | })(validParams[op]);
61 | }
62 |
63 | var unvalidParams = [
64 | "062413/3333",
65 | "038111/3029",
66 | "038211/3028",
67 | "038311/2928",
68 | "042111/321",
69 | "043111/929",
70 | "043211/149",
71 | "043311/3428",
72 | "044111/3728",
73 | "046311/3728",
74 | "047132/3028",
75 | "047230/3029",
76 | "047332/3026",
77 | "047431/3026",
78 | "048131/2326",
79 | "048311/2025",
80 | "983211/231",
81 | "983211/2125",
82 | "983231/1720",
83 | "073111/192",
84 | "073211/182",
85 | "073911/182",
86 | "076311/162",
87 | "077111/122",
88 | "078111/122",
89 | "083111/789",
90 | "093111/972",
91 | "430229/231",
92 | "431122/1321",
93 | "432122/1421",
94 | "432122/8763",
95 | "437122/212",
96 | "438122/872",
97 | "438131/1121",
98 | "438231/1120",
99 | "800122/768",
100 | "802222/817",
101 | "802222/1119",
102 | "982111/1619",
103 | "982111/1618"];
104 |
105 | for (var op in unvalidParams) {
106 | (function (item) {
107 | it('should check rc number ' + item + ' -> unvalid', function () {
108 | expect(validator.isAcceptable(item)).to.equal(false);
109 | });
110 | })(unvalidParams[op]);
111 | }
112 | });
113 |
--------------------------------------------------------------------------------
/test/customValidators/customValidators.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 |
6 | var Validation = require('../../src/validation/Validation.js');
7 | var Validators = require('../../src/validation/BasicValidators.js');
8 |
9 | var expect = require('expect.js');
10 | var _:UnderscoreStatic = require('underscore');
11 | import Q = require('q');
12 |
13 | var moment = require('moment');
14 | import icoValidator = require('../../src/customValidators/ICOValidator');
15 | import dateCompareValidator = require('../../src/customValidators/DateCompareValidator');
16 |
17 | /**
18 | * @name Custom async property validator example
19 | * @description
20 | * Return true for valid BranchOfBusiness, otherwise return false.
21 | *
22 | * To create a async custom validator you have to implement IAsyncPropertyValidator interface.
23 | * Async custom validator must have property isAsync set to true;
24 | */
25 | class BranchOfBusinessValidator {
26 |
27 | /**
28 | * It checks the list of all branches of business. Return true if passed branch of business exists.
29 | * @param s {string} value to check
30 | * @returns {boolean} return true for valid value, otherwise false
31 | */
32 | isAcceptable(s:string):Q.Promise {
33 | var deferred = Q.defer();
34 |
35 | setTimeout(function () {
36 | var items =
37 | [
38 | { "value": 1, "text": "machinery" },
39 | { "value": 2, "text": "agriculture" },
40 | { "value": 3, "text": "academic" },
41 | { "value": 4, "text": "goverment" }
42 | ];
43 |
44 | var hasSome = _.some(items, function (item) {
45 | return item.text == s;
46 | });
47 |
48 | if (hasSome) {
49 | deferred.resolve(true);
50 | }
51 | else {
52 | deferred.resolve(false);
53 | }
54 | }, 1000);
55 |
56 | return deferred.promise;
57 | }
58 |
59 | isAsync = true;
60 | tagName = "branchOfBusiness";
61 | }
62 |
63 | interface ICompany {
64 | Name:string;
65 | ICO:string;
66 | BranchOfBusiness:string;
67 | }
68 |
69 | /**
70 | * @name Custom async property validator example
71 | * @description
72 | * Return true for valid BranchOfBusiness, otherwise return false.
73 | *
74 | * To create a async custom validator you have to implement IAsyncPropertyValidator interface.
75 | * Async custom validator must have property isAsync set to true;
76 | */
77 | class DateCompareExtValidator extends dateCompareValidator {
78 | public isAcceptable(s:any) {
79 | //if date to compare is not specified - defaults to compare against now
80 | if (!_.isDate(s)) return false;
81 |
82 | var then = moment(s);
83 |
84 | if (this.CompareTo == undefined) this.CompareTo = new Date();
85 | var now = moment(this.CompareTo);
86 |
87 | if (this.CompareTo2 == undefined) this.CompareTo2 = new Date();
88 | var now2 = moment(this.CompareTo2);
89 | var isValid = this.isValid(now, then, this.CompareOperator) && this.isValid(now2, then, this.CompareOperator2);
90 |
91 | return isValid;
92 | }
93 |
94 | private isValid(now:any, then:any, compareOperator:Validation.CompareOperator) {
95 | var isValid = false;
96 | var diffs:number = then.diff(now);
97 | if (this.IgnoreTime) diffs = moment.duration(diffs).days();
98 |
99 | if (diffs < 0) {
100 | isValid = compareOperator == Validation.CompareOperator.LessThan
101 | || compareOperator == Validation.CompareOperator.LessThanEqual
102 | || compareOperator == Validation.CompareOperator.NotEqual;
103 | }
104 | else if (diffs > 0) {
105 | isValid = compareOperator == Validation.CompareOperator.GreaterThan
106 | || compareOperator == Validation.CompareOperator.GreaterThanEqual
107 | || compareOperator == Validation.CompareOperator.NotEqual;
108 | }
109 | else {
110 | isValid = compareOperator == Validation.CompareOperator.LessThanEqual
111 | || compareOperator == Validation.CompareOperator.Equal
112 | || compareOperator == Validation.CompareOperator.GreaterThanEqual;
113 | }
114 | return isValid;
115 | }
116 |
117 | tagName = "dataCompareExt";
118 |
119 | /**
120 | * Set the time of compare between passed date and CompareTo date.
121 | */
122 | public CompareOperator2:Validation.CompareOperator;
123 |
124 | /**
125 | * The datetime against the compare is done.
126 | * If CompareTo is not set, then comparison is done against actual datetime.
127 | */
128 | public CompareTo2:Date;
129 | }
130 |
131 | interface IDuration {
132 | From:Date;
133 | To:Date;
134 | }
135 |
136 | describe('custom validators', function () {
137 |
138 | describe('create new custom validator', function () {
139 |
140 | var required = new Validators.RequiredValidator();
141 | var ico = new icoValidator();
142 | var branchOfBusiness = new BranchOfBusinessValidator();
143 |
144 | var companyValidator = new Validation.AbstractValidator();
145 | companyValidator.RuleFor("ICO", required);
146 | companyValidator.RuleFor("ICO", ico);
147 |
148 | companyValidator.RuleFor("BranchOfBusiness", required);
149 | companyValidator.RuleFor("BranchOfBusiness", branchOfBusiness);
150 |
151 |
152 | beforeEach(function () {
153 | //setup
154 | this.Data = {};
155 | this.Validator = companyValidator.CreateRule("Company");
156 |
157 | });
158 |
159 | it('fill correct data - no errors', function (done) {
160 |
161 | //when
162 | this.Data.ICO = "12312312";
163 | this.Data.BranchOfBusiness = "machinery";
164 |
165 | //excercise
166 | var result = this.Validator.Validate(this.Data);
167 | var promiseResult = this.Validator.ValidateAsync(this.Data);
168 |
169 | promiseResult.then(function (response) {
170 |
171 | //verify
172 | expect(response.HasErrors).to.equal(false);
173 |
174 | done();
175 |
176 | }).done(null, done);
177 | });
178 |
179 | it('fill incorrect data - some errors', function (done) {
180 |
181 | //when
182 | this.Data.ICO = "11111111";
183 | this.Data.BranchOfBusiness = "unknown";
184 |
185 | //excercise
186 | var result = this.Validator.Validate(this.Data);
187 | var promiseResult = this.Validator.ValidateAsync(this.Data);
188 |
189 | promiseResult.then(function (response) {
190 |
191 | //verify
192 | expect(response.HasErrors).to.equal(true);
193 | expect(response.ErrorCount).to.equal(2);
194 |
195 | done();
196 |
197 | }).done(null, done);
198 | });
199 | });
200 |
201 |
202 | describe('extend existing validator with custom functionality', function () {
203 |
204 | var lowerThanOneYearAndGreaterThanToday = new DateCompareExtValidator();
205 | lowerThanOneYearAndGreaterThanToday.CompareOperator = Validation.CompareOperator.LessThan;
206 | lowerThanOneYearAndGreaterThanToday.CompareTo = moment(new Date()).add({year: 1}).toDate();
207 | lowerThanOneYearAndGreaterThanToday.CompareOperator2 = Validation.CompareOperator.GreaterThanEqual;
208 | lowerThanOneYearAndGreaterThanToday.CompareTo2 = new Date();
209 |
210 |
211 | var durationValidator = new Validation.AbstractValidator();
212 | durationValidator.RuleFor("From", lowerThanOneYearAndGreaterThanToday);
213 | durationValidator.RuleFor("To", lowerThanOneYearAndGreaterThanToday);
214 |
215 |
216 | beforeEach(function () {
217 | //setup
218 | this.Data = {};
219 | this.Validator = durationValidator.CreateRule("Duration");
220 |
221 | });
222 |
223 | it('fill correct data - no errors', function () {
224 |
225 | //when
226 | this.Data.From = moment(new Date()).add({days: 5}).toDate();
227 | this.Data.To = moment(new Date()).add({days: 360}).toDate();
228 |
229 | //excercise
230 | var result = this.Validator.Validate(this.Data);
231 |
232 | //verify
233 | expect(result.HasErrors).to.equal(false);
234 |
235 | });
236 |
237 | it('fill incorrect data - some errors', function () {
238 |
239 | //when
240 | this.Data.From = moment(new Date()).add({days: -1}).toDate();
241 | this.Data.To = moment(new Date()).add({days: 370}).toDate();
242 |
243 | //excercise
244 | var result = this.Validator.Validate(this.Data);
245 |
246 | //verify
247 | expect(result.HasErrors).to.equal(true);
248 | expect(result.ErrorCount).to.equal(2);
249 |
250 | });
251 | });
252 | });
--------------------------------------------------------------------------------
/test/validation/basicValidators.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 |
6 | //require["config"](
7 | // { baseUrl: '../../src/validation' }
8 | //);
9 |
10 |
11 | import Validation = require('../../src/validation/Validation');
12 | import Validators = require('../../src/validation/BasicValidators');
13 |
14 | var expect = require('expect.js');
15 | var _:UnderscoreStatic = require('underscore');
16 | import Q = require('q');
17 |
18 | describe('basic validators', function () {
19 |
20 | describe('Range validator', function () {
21 | var rangeValidator = new Validators.RemoteValidator();
22 | it('should return false when value is not in range',function(){
23 | var range = [5,11]
24 | var rangeValidator = new Validators.RangeValidator(range);
25 | expect(rangeValidator.isAcceptable(4)).to.equal(false);
26 | expect(rangeValidator.isAcceptable(12)).to.equal(false);
27 | }
28 | )
29 | it('should return true when value is in range',function(){
30 | var range = [5,11]
31 | var rangeValidator = new Validators.RangeValidator(range);
32 | expect(rangeValidator.isAcceptable(5)).to.equal(true);
33 | expect(rangeValidator.isAcceptable(7)).to.equal(true);
34 | expect(rangeValidator.isAcceptable(11)).to.equal(true);
35 | }
36 | )
37 | });
38 |
39 | describe('remote validator', function () {
40 | var remote = new Validators.RemoteValidator();
41 | remote.Options = {
42 | url:"http://api.automeme.net/text.json"
43 | }
44 |
45 |
46 | it('non-existing country code should return false', function (done) {
47 |
48 | var promiseResult =remote.isAcceptable('abc@gmail.com');
49 |
50 | promiseResult.then(function (response) {
51 | expect(response).to.equal(false);
52 |
53 | done();
54 | }).done(null, done);
55 | });
56 |
57 | // it('existing country code return true', function (done) {
58 | //
59 | // var promiseResult =remote.isAcceptable('abc@gmail.com')
60 | //
61 | // promiseResult.then(function (response) {
62 | // expect(response).to.equal(true);
63 | //
64 | // done();
65 | // }).done(null, done);
66 | // });
67 | });
68 | });
--------------------------------------------------------------------------------
/test/validation/rulesLists.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 |
6 | var Validation = require('../../src/validation/Validation.js');
7 | var Validators = require('../../src/validation/BasicValidators.js');
8 | var expect = require('expect.js');
9 | var _:UnderscoreStatic = require('underscore');
10 | import Q = require('q');
11 |
12 | interface IPerson{
13 | Checked:boolean;
14 | FirstName:string;
15 | LastName:string;
16 | Contacts:Array;
17 | }
18 | interface IContact{
19 | Email:string;
20 | Mobile:IPhone;
21 | FixedLine:IPhone;
22 | }
23 | interface IPhone{
24 | CountryCode:string
25 | Number:string
26 | }
27 |
28 | describe('validation rules for lists', function () {
29 |
30 | var required = new Validators.RequiredValidator();
31 |
32 |
33 | var createPersonValidator = function() {
34 |
35 | var maxLength = new Validators.MaxLengthValidator(15);
36 |
37 | var validator = new Validation.AbstractValidator();
38 | validator.RuleFor("FirstName", required);
39 | validator.RuleFor("FirstName", maxLength);
40 |
41 | validator.RuleFor("LastName", required);
42 | validator.RuleFor("LastName", maxLength);
43 |
44 | var contactValidator = createContactValidator();
45 | validator.ValidatorFor("Contacts",contactValidator,true);
46 |
47 | return validator;
48 | };
49 |
50 | var createContactValidator = function() {
51 |
52 | var validator = new Validation.AbstractValidator();
53 | validator.RuleFor("Email", required);
54 | validator.RuleFor("Email", new Validators.MaxLengthValidator(100));
55 | validator.RuleFor("Email", new Validators.EmailValidator());
56 |
57 | var phoneValidator = createPhoneValidator();
58 | validator.ValidatorFor("Mobile", phoneValidator);
59 | validator.ValidatorFor("FixedLine", phoneValidator);
60 |
61 | return validator;
62 | };
63 |
64 | var createPhoneValidator = function() {
65 |
66 | var validator = new Validation.AbstractValidator();
67 | validator.RuleFor("CountryCode", required);
68 | validator.RuleFor("CountryCode", new Validators.MaxLengthValidator(3));
69 |
70 | validator.RuleFor("Number", required);
71 | validator.RuleFor("Number", new Validators.MaxLengthValidator(9));
72 |
73 | var optionsFce = function() {
74 | var deferral = Q.defer();
75 | setTimeout(function () {
76 | deferral.resolve(["FRA","CZE","USA","GER"]);
77 | }, 500);
78 | return deferral.promise;
79 | };
80 |
81 | var param = new Validators.ContainsValidator();
82 | param.Options = optionsFce();
83 |
84 | validator.RuleFor("CountryCode", param);
85 |
86 | return validator;
87 | };
88 |
89 | var mainValidator = createPersonValidator();
90 |
91 |
92 | //setup
93 | var getData = function () {
94 | return {
95 | Checked: true,
96 | FirstName: "John",
97 | LastName: "Smith",
98 | Contacts: []
99 | }
100 | };
101 |
102 |
103 | var getItemDataTemplate = function() {
104 | return {
105 | Email: 'mail@gmail.com',
106 | Mobile: {
107 | CountryCode: 'CZE',
108 | Number: '736483690'
109 | },
110 | FixedLine: {
111 | CountryCode: 'USA',
112 | Number: '736483690'
113 | }
114 | }
115 | };
116 |
117 | beforeEach(function(){
118 |
119 |
120 | this.Data = getData();
121 | this.MainValidator = mainValidator.CreateRule("Main");
122 |
123 | });
124 | it('fill undefined - some errors', function (done) {
125 |
126 | //when
127 | this.Data.Contacts = undefined;
128 |
129 | //excercise
130 | var result = this.MainValidator.Validate(this.Data);
131 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
132 |
133 | //verify
134 | promiseResult.then(function (response) {
135 |
136 | //verify
137 | expect(response.HasErrors).to.equal(false);
138 |
139 | done();
140 |
141 | }).done(null,done);
142 | });
143 | it('fill correct data - no errors', function (done) {
144 |
145 | //when
146 | this.Data.Contacts.push(getItemDataTemplate());
147 | this.Data.Contacts.push(getItemDataTemplate());
148 | this.Data.Contacts.push(getItemDataTemplate());
149 |
150 | //excercise
151 | var result = this.MainValidator.Validate(this.Data);
152 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
153 |
154 | //verify
155 | promiseResult.then(function (response) {
156 |
157 | //verify
158 | expect(response.HasErrors).to.equal(false);
159 |
160 | done();
161 |
162 | }).done(null,done);
163 | });
164 |
165 |
166 | it('fill incorrect data - some errors', function (done) {
167 |
168 | //when
169 | this.Data.Contacts.push(getItemDataTemplate());
170 | this.Data.Contacts.push(getItemDataTemplate());
171 | this.Data.Contacts.push(getItemDataTemplate());
172 |
173 | //simulate error at second item in list
174 | this.Data.Contacts[1].Email = "";
175 |
176 | //simulate async error at third item in list
177 | this.Data.Contacts[2].Mobile.CountryCode = "BLA";
178 |
179 | //excercise
180 | var result = this.MainValidator.Validate(this.Data);
181 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
182 |
183 | //verify
184 | promiseResult.then(function (response) {
185 |
186 | //verify
187 | expect(response.HasErrors).to.equal(true);
188 | expect(response.Errors["Contacts"].HasErrors).to.equal(true);
189 | expect(response.Errors["Contacts"].Children[0].HasErrors).to.equal(false);
190 | expect(response.Errors["Contacts"].Children[1].HasErrors).to.equal(true);
191 | expect(response.Errors["Contacts"].Children[2].HasErrors).to.equal(true);
192 |
193 | done();
194 |
195 | }).done(null,done);
196 | });
197 |
198 | it('delete error item, leave correct item - no errors', function (done) {
199 |
200 | //when
201 | this.Data.Contacts.push(getItemDataTemplate());
202 | this.Data.Contacts.push(getItemDataTemplate());
203 | this.Data.Contacts.push(getItemDataTemplate());
204 |
205 | //item list property error
206 | this.Data.Contacts[2].Email = "";
207 |
208 | //item list async property error
209 | this.Data.Contacts[2].Mobile.CountryCode = "BLA";
210 |
211 | //delete last error item
212 | this.Data.Contacts.splice(2,1)
213 |
214 | //excercise
215 | var result = this.MainValidator.Validate(this.Data);
216 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
217 |
218 | //verify
219 | promiseResult.then(function (response) {
220 |
221 | //verify
222 | expect(response.HasErrors).to.equal(false);
223 | expect(response.Errors["Contacts"].HasErrors).to.equal(false);
224 | expect(response.Errors["Contacts"].Children[0].HasErrors).to.equal(false);
225 | expect(response.Errors["Contacts"].Children[1].HasErrors).to.equal(false);
226 |
227 | done();
228 |
229 | }).done(null,done);
230 | });
231 |
232 | it('delete correct item, leave error item - some errors', function (done) {
233 |
234 | //when
235 | this.Data.Contacts.push(getItemDataTemplate());
236 | this.Data.Contacts.push(getItemDataTemplate());
237 | this.Data.Contacts.push(getItemDataTemplate());
238 |
239 | //item list property error
240 | this.Data.Contacts[2].Email = "";
241 |
242 | //item list async property error
243 | this.Data.Contacts[2].Mobile.CountryCode = "BLA";
244 |
245 | //delete correct item
246 | this.Data.Contacts.splice(1,1);
247 |
248 | //excercise
249 | var result = this.MainValidator.Validate(this.Data);
250 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
251 |
252 | //verify
253 | promiseResult.then(function (response) {
254 |
255 | //verify
256 | expect(response.HasErrors).to.equal(true);
257 | expect(response.Errors["Contacts"].HasErrors).to.equal(true);
258 | expect(response.Errors["Contacts"].Children[0].HasErrors).to.equal(false);
259 | expect(response.Errors["Contacts"].Children[1].HasErrors).to.equal(true);
260 |
261 | done();
262 |
263 | }).done(null,done);
264 | });
265 |
266 | });
267 |
268 |
--------------------------------------------------------------------------------
/test/validation/rulesNested.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 |
6 | var Validation = require('../../src/validation/Validation.js');
7 | var Validators = require('../../src/validation/BasicValidators.js');
8 | var Utils = require('../../src/validation/Utils.js');
9 | var expect = require('expect.js');
10 | var _:UnderscoreStatic = require('underscore');
11 | import Q = require('q');
12 |
13 | interface IData{
14 | Person1:IPerson
15 | Person2:IPerson
16 | }
17 | interface IPerson{
18 | Checked:boolean;
19 | FirstName:string;
20 | LastName:string;
21 | Contact:IContact;
22 | }
23 | interface IContact{
24 | Email:string;
25 | Mobile:IPhone;
26 | FixedLine:IPhone;
27 | }
28 | interface IPhone{
29 | CountryCode:string
30 | Number:string
31 | }
32 |
33 | describe('nested validation rules', function () {
34 |
35 | var required = new Validators.RequiredValidator();
36 |
37 | var createMainValidator = function(){
38 | var validator = new Validation.AbstractValidator();
39 |
40 | var personValidator = createPersonValidator();
41 | validator.ValidatorFor("Person1",personValidator);
42 | validator.ValidatorFor("Person2",personValidator);
43 |
44 | return validator;
45 | };
46 |
47 | var createPersonValidator = function() {
48 |
49 | var maxLength = new Validators.MaxLengthValidator(15);
50 |
51 | var validator = new Validation.AbstractValidator();
52 | validator.RuleFor("FirstName", required);
53 | validator.RuleFor("FirstName", maxLength);
54 |
55 | validator.RuleFor("LastName", required);
56 | validator.RuleFor("LastName", maxLength);
57 |
58 | var contactValidator = createContactValidator();
59 | validator.ValidatorFor("Contact",contactValidator);
60 |
61 | return validator;
62 | };
63 |
64 | var createContactValidator = function() {
65 |
66 | var validator = new Validation.AbstractValidator();
67 | validator.RuleFor("Email", required);
68 | validator.RuleFor("Email", new Validators.MaxLengthValidator(100));
69 | validator.RuleFor("Email", new Validators.EmailValidator());
70 |
71 | var phoneValidator = createPhoneValidator();
72 | validator.ValidatorFor("Mobile", phoneValidator);
73 | validator.ValidatorFor("FixedLine", phoneValidator);
74 |
75 | return validator;
76 | };
77 |
78 | var createPhoneValidator = function() {
79 |
80 | var validator = new Validation.AbstractValidator();
81 | validator.RuleFor("CountryCode", required);
82 | validator.RuleFor("CountryCode", new Validators.MaxLengthValidator(3));
83 |
84 | validator.RuleFor("Number", required);
85 | validator.RuleFor("Number", new Validators.MaxLengthValidator(9));
86 |
87 | var optionsFce = function() {
88 | var deferral = Q.defer();
89 | setTimeout(function () {
90 | deferral.resolve(["FRA","CZE","USA","GER"]);
91 | }, 500);
92 | return deferral.promise;
93 | };
94 |
95 | var param = new Validators.ContainsValidator();
96 | param.Options = optionsFce();
97 |
98 | validator.RuleFor("CountryCode", param);
99 |
100 | return validator;
101 | };
102 |
103 | var mainValidator = createMainValidator();
104 |
105 | beforeEach(function(){
106 |
107 | //setup
108 | var getData = function () {
109 | var contact = {
110 | Email:'mail@gmail.com',
111 | Mobile:{
112 | CountryCode:'CZE',
113 | Number:'736483690'
114 | },
115 | FixedLine:{
116 | CountryCode:'USA',
117 | Number:'736483690'
118 | }
119 | };
120 | return{
121 | Person1: {
122 | Checked:true,
123 | FirstName: "John",
124 | LastName: "Smith",
125 | Contact: contact
126 | },
127 | Person2: {
128 | Checked:true,
129 | FirstName: "Adam",
130 | LastName: "Novak",
131 | Contact: contact
132 | }
133 | }
134 | };
135 |
136 | this.Data = getData();
137 | this.MainValidator = mainValidator.CreateRule("Main");
138 |
139 | });
140 |
141 | it('fill correct data - no errors', function (done) {
142 |
143 | //when
144 |
145 | //excercise
146 | var result = this.MainValidator.Validate(this.Data);
147 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
148 |
149 | //verify
150 | promiseResult.then(function (response) {
151 |
152 | //verify
153 | expect(response.HasErrors).to.equal(false);
154 |
155 | done();
156 |
157 | }).done(null,done);
158 | });
159 |
160 |
161 | it('fill incorrect data - some errors', function (done) {
162 |
163 | //when
164 | //nested property error
165 | this.Data.Person1.Contact.Email = "";
166 |
167 | //async nested property error
168 | this.Data.Person1.Contact.Mobile.CountryCode = "BLA";
169 |
170 | //excercise
171 | var result = this.MainValidator.Validate(this.Data);
172 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
173 |
174 | //verify
175 | promiseResult.then(function (response) {
176 |
177 | //verify
178 | expect(response.HasErrors).to.equal(true);
179 |
180 | done();
181 |
182 | }).done(null,done);
183 | });
184 |
185 |
186 | describe("fill incorrect data - rule optional", function() {
187 |
188 | beforeEach(function () {
189 | //setup
190 |
191 | //set rule optional when checked !=true;
192 | var optional = function () {
193 | return !this.Checked;
194 | }.bind(this.Data);
195 |
196 |
197 | this.MainValidator.SetOptional(optional);
198 |
199 | //nested error
200 | this.Data.Person1.Contact.Email = "";
201 |
202 | //async nested error
203 | this.Data.Person1.Contact.Mobile.CountryCode = "BLA";
204 |
205 | });
206 |
207 | it('is optional -> no errors', function (done) {
208 |
209 | //when
210 | this.Data.Person1.Checked = false;
211 | this.Data.Person2.Checked = false;
212 |
213 | //excercise
214 | var result = this.MainValidator.Validate(this.Data);
215 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
216 |
217 | //verify
218 | promiseResult.then(function (response) {
219 |
220 | //verify
221 | expect(response.HasErrors).to.equal(false);
222 |
223 | done();
224 |
225 | }).done(null, done);
226 | });
227 |
228 |
229 | it('is not optional - some errors', function (done) {
230 |
231 | //when
232 | this.Data.Person1.Checked = true;
233 | this.Data.Person2.Checked = true;
234 |
235 | //excercise
236 | var result = this.MainValidator.Validate(this.Data);
237 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
238 |
239 | //verify
240 | promiseResult.then(function (response) {
241 |
242 | //verify
243 | expect(response.HasErrors).to.equal(false);
244 |
245 | done();
246 |
247 | }).done(null, done);
248 | });
249 | });
250 |
251 | describe("Dot syntax", function () {
252 | it('fill correct data - no errors', function (done) {
253 |
254 | //when
255 |
256 | //excercise
257 | var result = this.MainValidator.Validate(this.Data);
258 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
259 |
260 |
261 |
262 | var compDotObject = Utils.CompositeDotObject.Transform(this.MainValidator);
263 |
264 | //verify
265 | promiseResult.then(function (response) {
266 |
267 | var dotResult = Utils.CompositeDotObject.Transform(result);
268 |
269 | //verify
270 | expect(response.HasErrors).to.equal(false);
271 |
272 | expect(dotResult.Main.Person1.Contact.Email.HasErrors).to.equal(false);
273 | expect(dotResult.Main.Person1.Contact.Mobile.CountryCode.HasErrors).to.equal(false);
274 |
275 |
276 | expect(compDotObject.Main.Person1.Contact.Rules["Email"].HasErrors).to.equal(false);
277 | expect(compDotObject.Main.Person1.Contact.Mobile.Rules["CountryCode"].HasErrors).to.equal(false);
278 |
279 | done();
280 |
281 | }).done(null, done);
282 | });
283 |
284 | it('fill incorrect data - some errors', function (done) {
285 |
286 | //when
287 | //nested property error
288 | this.Data.Person1.Contact.Email = "";
289 |
290 | //async nested property error
291 | this.Data.Person1.Contact.Mobile.CountryCode = "BLA";
292 |
293 |
294 | //excercise
295 | var result = this.MainValidator.Validate(this.Data);
296 | var promiseResult = this.MainValidator.ValidateAsync(this.Data);
297 |
298 | var compDotObject = Utils.CompositeDotObject.Transform(this.MainValidator);
299 |
300 | //verify
301 | promiseResult.then(function (response) {
302 | var dotResult = Utils.CompositeDotObject.Transform(result);
303 |
304 | //verify
305 | expect(response.HasErrors).to.equal(true);
306 |
307 |
308 | expect(dotResult.Main.Person1.Contact.Email.HasErrors).to.equal(true);
309 | expect(dotResult.Main.Person1.Contact.Mobile.CountryCode.HasErrors).to.equal(true);
310 |
311 |
312 | expect(compDotObject.Main.Person1.Contact.Rules["Email"].HasErrors).to.equal(true);
313 | expect(compDotObject.Main.Person1.Contact.Mobile.Rules["CountryCode"].HasErrors).to.equal(true);
314 |
315 | done();
316 |
317 | }).done(null, done);
318 |
319 | });
320 | });
321 | });
322 |
323 |
--------------------------------------------------------------------------------
/test/validation/rulesShared.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 | ///
4 | ///
5 |
6 | var Validation = require('../../src/validation/Validation.js');
7 | var Validators = require('../../src/validation/BasicValidators.js');
8 | var expect = require('expect.js');
9 | var _:UnderscoreStatic = require('underscore');
10 | import Q = require('q');
11 |
12 | interface IPerson{
13 | Checked:boolean;
14 | FirstName:string;
15 | LastName:string;
16 | Contacts:Array;
17 | }
18 | interface IContact{
19 | Email:string;
20 | Mobile:IPhone;
21 | FixedLine:IPhone;
22 | }
23 | interface IPhone{
24 | CountryCode:string
25 | Number:string
26 | }
27 |
28 | describe('validation rules for shared validations', function () {
29 |
30 | var required = new Validators.RequiredValidator();
31 |
32 | var createPersonValidator = function() {
33 |
34 | var maxLength = new Validators.MaxLengthValidator(15);
35 |
36 | var validator = new Validation.AbstractValidator();
37 | validator.RuleFor("FirstName", required);
38 | validator.RuleFor("FirstName", maxLength);
39 |
40 | validator.RuleFor("LastName", required);
41 | validator.RuleFor("LastName", maxLength);
42 |
43 | var contactValidator = createContactValidator();
44 | validator.ValidatorFor("Contacts",contactValidator,true);
45 |
46 | var uniqContact = function(args){
47 | args.HasError = false;
48 | args.ErrorMessage = "";
49 | var fullNames =_.map(this.Contacts,function(contact:any){return contact.Email});
50 | var itemcounts = _.countBy(fullNames, function (n) { return n; });
51 | var dupes = _.reduce(itemcounts, function (memo:Array, item, idx) {
52 | if (item > 1)
53 | memo.push(idx);
54 | return memo;
55 | }, []);
56 |
57 | if (dupes.length != 0) {
58 | args.HasError = true;
59 | args.ErrorMessage = _.reduce(dupes, function (memo:string, fullName:string) {
60 | return memo + fullName + " ";
61 | },"Each contact must be unique. Not unique values: ");
62 |
63 | return;
64 | }
65 | };
66 |
67 | validator.Validation({Name:"UniqueContact",ValidationFce:uniqContact});
68 |
69 | return validator;
70 | };
71 |
72 | var createContactValidator = function() {
73 |
74 | var validator = new Validation.AbstractValidator();
75 | validator.RuleFor("Email", required);
76 | validator.RuleFor("Email", new Validators.MaxLengthValidator(100));
77 | validator.RuleFor("Email", new Validators.EmailValidator());
78 |
79 | var phoneValidator = createPhoneValidator();
80 | validator.ValidatorFor("Mobile", phoneValidator);
81 | validator.ValidatorFor("FixedLine", phoneValidator);
82 |
83 | var uniqPhoneNumber = function(args){
84 | args.HasError = false;
85 | args.ErrorMessage = "";
86 | if (this.Mobile.Number == this.FixedLine.Number) {
87 | args.HasError = true;
88 | args.ErrorMessage = "Each phone number must be unique.";
89 | return;
90 | }
91 | };
92 |
93 | validator.Validation({Name:"UniqPhoneNumber",ValidationFce:uniqPhoneNumber});
94 |
95 | //validator.GroupFor("MobileContact",namedUniqPhoneNumber);
96 |
97 |
98 |
99 | return validator;
100 | };
101 |
102 | var createPhoneValidator = function() {
103 |
104 | var validator = new Validation.AbstractValidator();
105 | validator.RuleFor("CountryCode", required);
106 | validator.RuleFor("CountryCode", new Validators.MaxLengthValidator(3));
107 |
108 | validator.RuleFor("Number", required);
109 | validator.RuleFor("Number", new Validators.MaxLengthValidator(9));
110 |
111 | var optionsFce = function() {
112 | var deferral = Q.defer();
113 | setTimeout(function () {
114 | deferral.resolve(["FRA","CZE","USA","GER"]);
115 | }, 500);
116 | return deferral.promise;
117 | };
118 |
119 | var param = new Validators.ContainsValidator();
120 | param.Options = optionsFce();
121 |
122 | validator.RuleFor("CountryCode", param);
123 |
124 | return validator;
125 | };
126 |
127 | var mainValidator = createPersonValidator();
128 |
129 |
130 | //setup
131 | var getData = function () {
132 | return {
133 | Checked: true,
134 | FirstName: "",
135 | LastName: "",
136 | Contacts: []
137 | }
138 | };
139 |
140 |
141 | var getItemDataTemplate = function(mail?:string) {
142 | if (mail == undefined) mail = 'mail@gmail.com';
143 | return {
144 | Email: mail,
145 | Mobile: {
146 | CountryCode: 'CZE',
147 | Number: '736483690'
148 | },
149 | FixedLine: {
150 | CountryCode: 'USA',
151 | Number: '736483691'
152 | }
153 | }
154 | };
155 |
156 | describe("call specific validator",function() {
157 | beforeEach(function () {
158 |
159 |
160 | this.Data = getData();
161 | this.MainValidator = mainValidator.CreateRule("Main");
162 |
163 | });
164 |
165 |
166 | it('no errors', function () {
167 |
168 | //when
169 | this.Data.Contacts.push(getItemDataTemplate('mail1@gmail.com'));
170 | this.Data.Contacts.push(getItemDataTemplate('mail2@gmail.com'));
171 | this.Data.Contacts.push(getItemDataTemplate('mail3@gmail.com'));
172 |
173 | //find the validator by name
174 | var validator = this.MainValidator.Validators["UniqueContact"];
175 | //excercise
176 | var result = validator.Validate(this.Data);
177 |
178 | //verify by return value
179 | expect(result.HasError).to.equal(false);
180 |
181 | //verify by validator properties
182 | expect(validator.HasErrors).to.equal(false);
183 |
184 | });
185 | it('some errors', function () {
186 |
187 | //when
188 | this.Data.Contacts.push(getItemDataTemplate('mail1@gmail.com'));
189 | this.Data.Contacts.push(getItemDataTemplate('mail2@gmail.com'));
190 | this.Data.Contacts.push(getItemDataTemplate('mail2@gmail.com'));
191 |
192 | //find the validator by name
193 | var validator = this.MainValidator.Validators["UniqueContact"];
194 | //excercise
195 | var result = validator.Validate(this.Data);
196 |
197 | //verify by return value
198 | expect(result.HasError).to.equal(true);
199 |
200 | //verify by validator properties
201 | expect(validator.HasErrors).to.equal(true);
202 |
203 | });
204 | })
205 | });
206 |
207 |
--------------------------------------------------------------------------------
/tsd.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "v4",
3 | "repo": "borisyankov/DefinitelyTyped",
4 | "ref": "master",
5 | "path": "typings",
6 | "bundle": "typings/tsd.d.ts",
7 | "installed": {
8 | "expect.js/expect.js.d.ts": {
9 | "commit": "d3f6bcccdeb052003c96a7c4adbb002828c2a8ae"
10 | },
11 | "mocha/mocha.d.ts": {
12 | "commit": "d3f6bcccdeb052003c96a7c4adbb002828c2a8ae"
13 | },
14 | "node/node.d.ts": {
15 | "commit": "d3f6bcccdeb052003c96a7c4adbb002828c2a8ae"
16 | },
17 | "underscore/underscore.d.ts": {
18 | "commit": "6f3946e020abbdefe93341d9e95a0054adb7d091"
19 | },
20 | "q/Q.d.ts": {
21 | "commit": "17f8e5aca2392978baf15a142410e3eedcc335cc"
22 | },
23 | "moment/moment.d.ts": {
24 | "commit": "5c000a23b5d00efe35ab0fcc3b568f71f3aa23c8"
25 | },
26 | "jquery/jquery.d.ts": {
27 | "commit": "17f8e5aca2392978baf15a142410e3eedcc335cc"
28 | },
29 | "underscore.string/underscore.string.d.ts": {
30 | "commit": "5c000a23b5d00efe35ab0fcc3b568f71f3aa23c8"
31 | },
32 | "hashmap/hashmap.d.ts": {
33 | "commit": "3505d15d991ddaa4f5efa13edcd8543bae1e46de"
34 | },
35 | "sinon/sinon.d.ts": {
36 | "commit": "bba33bcb0b363ae41db8517a09d1a4d07828616b"
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------