File / Directory |
Mutation score |
# Killed |
# Survived |
# Timeout |
# No coverage |
# Runtime errors |
# Transpile errors |
Total detected |
Total undetected |
Total mutants | |
---|---|---|---|---|---|---|---|---|---|---|---|
jedi-validate.js | 37.24 | 53 | 91 | 1 | 0 | 0 | 0 | 54 | 91 | 145 |
import deepmerge from './lib/deepmerge';
import { getData, getInputData, getValueByName } from './lib/get-data';
import { convertData } from './lib/convert-data';
import Dictionary from './i18n/jedi-validate-i18n';
import { getFormOptions, getInputRules } from './lib/get-options';
import { validateData, validateField } from './lib/validate-data';
import { ajax } from './lib/ajax';
import { initErrorMessages, markField } from './lib/utils';
import defaultMethods from './lib/methods';
import defaultOptions from './options';
/**
* JediValidate - validation
*/
export default class JediValidate {
/**
* Object with fields
* @private
* @type {Object.<string, Element>}
*/
fields = {};
/**
* Object with inputs nodes
* @private
* @type {Object.<string, HTMLInputElement|HTMLSelectElement|Array>}
*/
inputs = {};
/**
* Object with message nodes
* @private
* @type {Object.<string, Element>}
*/
messages = {};
/**
* Object with error message
* @private
* @type {Object.<string, Object.<string, string>>}
*/
errorMessages = {};
/**
* Object with error message
* @private
* @type {object} - data object
*/
data = {};
/**
* Validate methods
* @private
* @type {Object.<string, {func: Function, message: string}>}
*/
methods = 0{}{ ...defaultMethods };
/* eslint-disable */
/**
* Validator options
* @private
* @type {{ajax: {url: string, enctype: string, sendType: string, method: string}, rules: {}, messages: {}, containers: {parent: string, message: string, baseMessage: string}, states: {error: string, valid: string, pristine: string, dirty: string}, formStatePrefix: string, callbacks: {success: function, error: function}, clean: boolean, redirect: boolean, language: string, translations: {}}}
*/
options = {};
/* eslint-enable */
/**
* Validator rules
* @private
* @type {object}
*/
rules = {};
/**
* Translation dictionary
* @private
* @type {Dictionary}
*/
dictionary = null;
/**
* Elements
* @private
* @type {object}
*/
nodes = null;
/**
* Root element
* @private
* @type {Element}
*/
root = null;
/**
* JediValidate
* @param {HTMLElement} root - element which wraps form element
* @param {object} options - object with options
*/
constructor(root, options = {}) 1{}{
this.root = root;
const baseMessageClass =
2false3options.containers && options.containers.baseMessage && defaultOptions.containers.baseMessage4true(5options.containers || options.containers.baseMessage6false7trueoptions.containers && options.containers.baseMessage) || defaultOptions.containers.baseMessage;
this.nodes = 8{}{
form: this.root.querySelector(9""'form'),
inputs: this.root.querySelectorAll(10""'form [name]'),
baseMessage: this.root.querySelector(11""`.${baseMessageClass}`),
};
const formOptions = getFormOptions(this.nodes.form);
this.options = deepmerge(this.options, defaultOptions);
this.options = deepmerge(this.options, formOptions);
this.options = deepmerge(this.options, options);
this.rules = 12{}{ ...this.options.rules };
this.dictionary = new Dictionary(this.options.translations);
this.ready();
this.errorMessages = initErrorMessages(this.rules, this.options.messages, this.methods);
}
/**
* Ready
* @private
*/
ready() 13{}{
this.nodes.form.setAttribute(14""'novalidate', 15""'novalidate');
this.nodes.form.addEventListener(16""'submit', this.handleSubmit);
Array.from(this.nodes.inputs).forEach(input => 17{}{
// fixme "name" and "name in data" not the same
// name === "phone[]",
// data: { phone: [] } - name === "phone"
const name = input.name; // eslint-disable-line prefer-destructuring
if (18false19truethis.inputs[name]) 20{}{
if (21false22trueArray.isArray(this.inputs[name])) 23{}{
this.inputs[name].push(input);
} else 24{}{
const groupInput = 25[][this.inputs[name], input];
groupInput.name = name;
this.inputs[name] = groupInput;
}
} else 26{}{
this.inputs[name] = input;
let field = input.parentNode;
do 27{}{
if (28false29truefield.classList.contains(this.options.containers.parent)) 30{}{
this.fields[name] = field;
break;
}
field = field.parentNode;
} while (31false32field || field.classListfield && field.classList);
if (33false34true35this.fields[name]!this.fields[name]) 36{}{
console.warn(37""`Input ${name} has no parent field`);
delete this.inputs[name];
return;
}
this.fields[name].classList.add(this.options.states.pristine);
const messageElement = this.fields[name].querySelector(38""`.${this.options.containers.message}`);
if (39false40truemessageElement) 41{}{
this.messages[name] = messageElement;
} else 42{}{
this.messages[name] = document.createElement(43""'div');
this.messages[name].classList.add(this.options.containers.message);
this.fields[name].appendChild(this.messages[name]);
}
this.rules[name] = 44this.rules[name] && {}45false46truethis.rules[name] || {};
const inputRules = getInputRules(input);
this.rules[name] = deepmerge(inputRules, this.rules[name]);
Object.keys(this.rules[name]).forEach(rule => 47{}{
if (48false49truethis.rules[name][rule]) 50{}{
this.fields[name].classList.add(rule);
}
});
}
input.addEventListener(51""'change', this.handleInputChange.bind(this, name));
input.addEventListener(52""'input', this.handleInputInput.bind(this, name));
});
}
/**
* Handle input change
* @private
* @param {string} name
*/
handleInputChange(name) 53{}{
this.fields[name].classList.remove(this.options.states.dirty);
const inputData = getInputData(this.inputs[name]);
const value = getValueByName(name, inputData);
// fixme don't work with 2 inputs phone[]
this.data = 54{}{
...this.data,
...inputData,
};
const errors = validateField(
this.rules[name],
this.methods,
value,
name,
this.errorMessages,
this.data,
this.translate,
);
markField(this.fields[name], this.messages[name], this.options.states, errors);
}
/**
* Handle input
* @private
* @param {string} name
*/
handleInputInput(name) 55{}{
this.fields[name].classList.remove(this.options.states.pristine);
this.fields[name].classList.add(this.options.states.dirty);
}
/**
* Handle form submit
* @private
* @param {Event} event
*/
handleSubmit = event => 56{}{
this.data = getData(this.inputs);
const errors = validateData(this.rules, this.methods, this.data, this.errorMessages, this.translate);
const fieldNames = Object.keys(errors).filter(name => this.fields[name]);
if (57false58fieldNames.length === 059truefieldNames.length !== 0) 60{}{
fieldNames.forEach(name =>
markField(this.fields[name], this.messages[name], this.options.states, errors[name]),
);
}
const errorFieldNames = fieldNames.filter(name => errors[name]);
if (61false62true63errorFieldNames.length === 0errorFieldNames.length !== 0) 64{}{
try 65{}{
this.options.callbacks.error(66{}{ errors });
} catch (e) 67{}{
if (68false69true70process.env.NODE_ENV !== 'development'process.env.NODE_ENV === 71""'development') 72{}{
console.error(e);
}
}
event.preventDefault();
return;
}
if (73false74true75this.options.ajax || this.options.ajax.urlthis.options.ajax && this.options.ajax.url) 76{}{
event.preventDefault();
} else 77{}{
try 78{}{
this.options.callbacks.success(79{}{ event });
} catch (e) 80{}{
if (81false82true83process.env.NODE_ENV !== 'development'process.env.NODE_ENV === 84""'development') 85{}{
console.error(e);
}
}
return;
}
const convertedData = convertData(this.data, this.options.ajax.sendType);
this.send(86{}{
...this.options.ajax,
data: convertedData,
});
};
/**
* Translate
* @private
* @param {string} text - text to translate
*/
translate = text => this.dictionary.translate(text, this.options.language);
/**
* Send form
* @private
* @param {object} options - object with options for sending
* @param {string} options.url
* @param {string} options.enctype
* @param {string} options.sendType
* @param {string} options.method
* @param {string|FormData} options.data
*/
send(options) 87{}{
ajax(options, this.translate)
.then(response => 88{}{
if (89false90trueresponse.validationErrors) 91{}{
try 92{}{
this.options.callbacks.error(93{}{
errors: response.validationErrors,
});
} catch (e) 94{}{
if (95false96true97process.env.NODE_ENV !== 'development'process.env.NODE_ENV === 98""'development') 99{}{
console.error(e);
}
}
if (100false101trueresponse.validationErrors.base) 102{}{
this.nodes.baseMessage.innerHTML = response.validationErrors.base.join(103""', ');
this.root.classList.add(104this.options.formStatePrefix - this.options.states.errorthis.options.formStatePrefix + this.options.states.error);
this.root.classList.remove(105this.options.formStatePrefix - this.options.states.validthis.options.formStatePrefix + this.options.states.valid);
delete response.validationErrors.base;
} else 106{}{
this.nodes.baseMessage.innerHTML = 107"Stryker was here!"'';
}
Object.keys(response.validationErrors).forEach(name =>
markField(
this.fields[name],
this.messages[name],
this.options.states,
response.validationErrors[name],
),
);
} else 108{}{
try 109{}{
this.options.callbacks.success(110{}{ response });
} catch (e) 111{}{
if (112false113true114process.env.NODE_ENV !== 'development'process.env.NODE_ENV === 115""'development') 116{}{
console.error(e);
}
}
if (117false118true119this.options.redirect || response.redirectthis.options.redirect && response.redirect) 120{}{
window.location.href = response.redirect;
return;
}
if (121false122truethis.options.clean) 123{}{
this.nodes.form.reset();
}
}
})
.catch(({ method, url, status, statusText }) => 124{}{
console.warn(125""`${method} ${url} ${status} (${statusText})`);
this.nodes.baseMessage.innerHTML = this.translate(126""'Can not send form!');
this.root.classList.add(127this.options.formStatePrefix - this.options.states.errorthis.options.formStatePrefix + this.options.states.error);
this.root.classList.remove(128this.options.formStatePrefix - this.options.states.validthis.options.formStatePrefix + this.options.states.valid);
});
}
/**
* Collect data
* @public
* @param {string|Array.<string>} params - field
* @returns {Object}
*/
collect(params = 129"Stryker was here!"'') 130{}{
if (131false132true133params!params) 134{}{
this.data = getData(this.inputs);
return this.data;
}
if (135true136falseArray.isArray(params)) 137{}{
return params.reduce((collected, name) => 138{}{
const inputData = getInputData(this.inputs[name]);
this.data = 139{}{
...this.data,
...inputData,
};
return 140{}{
...collected,
...inputData,
};
}, {});
}
const inputData = getInputData(this.inputs[params]);
// fixme don't work with 2 inputs phone[]
this.data = 141{}{
...this.data,
...inputData,
};
return inputData;
}
/**
* Add rule to validator
* @public
* @param {string} rule - rule name
* @param {Function} func - function
* @param {string} message - error message
*/
addMethod(rule, func, message) 142{}{
this.methods[rule] = 143{}{
func,
message,
};
this.errorMessages = initErrorMessages(this.rules, this.options.messages, this.methods);
}
/**
* Add localization to JediValidate
* @public
* @param {string} sourceText - text on english
* @param {string} translatedText - text on needed language
* @param {string} language - language
*/
addToDictionary(sourceText, translatedText, language) 144{}{
this.dictionary.addTranslation(sourceText, translatedText, language);
}
}
# | Mutator | State | Location | Original | Replacement |
---|---|---|---|---|---|
0 | ObjectLiteral | Killed | 55 : 14 | { ...... } |
{} |
1 | Block | Killed | 98 : 36 | {
... } |
{} |
2 | ConditionalExpression | Survived | 102 : 12 | ( ... . |
|
3 | BinaryExpression | Survived | 102 : 12 | ( ... . |
. ... . |
4 | ConditionalExpression | Survived | 102 : 12 | ( ... . |
|
5 | BinaryExpression | Killed | 102 : 13 | . ... . |
. ... . |
6 | ConditionalExpression | Survived | 102 : 13 | . ... . |
|
7 | ConditionalExpression | Survived | 102 : 13 | . ... . |
|
8 | ObjectLiteral | Killed | 104 : 21 | {
... } |
{} |
9 | StringLiteral | Killed | 105 : 42 | ' ' |
"" |
10 | StringLiteral | Killed | 106 : 47 | ' [ ]' |
"" |
11 | StringLiteral | Killed | 107 : 49 | `.${ ... }` |
"" |
12 | ObjectLiteral | Killed | 116 : 21 | { ...... } |
{} |
13 | Block | Killed | 129 : 12 | {
... } |
{} |
14 | StringLiteral | Killed | 130 : 37 | ' ' |
"" |
15 | StringLiteral | Survived | 130 : 51 | ' ' |
"" |
16 | StringLiteral | Survived | 132 : 41 | ' ' |
"" |
17 | Block | Killed | 134 : 55 | {
... } |
{} |
18 | IfStatement | Survived | 140 : 16 | . [ ] |
|
19 | IfStatement | Killed | 140 : 16 | . [ ] |
|
20 | Block | Survived | 140 : 35 | {
... } |
{} |
21 | IfStatement | Survived | 141 : 20 | . ... ]) |
|
22 | IfStatement | Survived | 141 : 20 | . ... ]) |
|
23 | Block | Survived | 141 : 54 | {
... } |
{} |
24 | Block | Survived | 143 : 23 | {
... } |
{} |
25 | ArrayLiteral | Survived | 144 : 39 | [ ... ] |
[] |
26 | Block | Killed | 148 : 19 | {
... } |
{} |
27 | Block | TimedOut | 153 : 19 | {
... } |
{} |
28 | IfStatement | Killed | 154 : 24 | . ... ) |
|
29 | IfStatement | Killed | 154 : 24 | . ... ) |
|
30 | Block | Killed | 154 : 82 | {
... } |
{} |
31 | DoStatement | Killed | 160 : 25 | && . |
|
32 | BinaryExpression | Survived | 160 : 25 | && . |
|| . |
33 | IfStatement | Survived | 162 : 20 | ! ... ] |
|
34 | IfStatement | Killed | 162 : 20 | ! ... ] |
|
35 | PrefixUnaryExpression | Killed | 162 : 20 | ! ... ] |
. [ ] |
36 | Block | Survived | 162 : 40 | {
... } |
{} |
37 | StringLiteral | Survived | 163 : 33 | ` ... ` |
"" |
38 | StringLiteral | Killed | 170 : 71 | `.${ ... }` |
"" |
39 | IfStatement | Survived | 172 : 20 |
|
|
40 | IfStatement | Killed | 172 : 20 |
|
|
41 | Block | Survived | 172 : 36 | {
... } |
{} |
42 | Block | Killed | 174 : 23 | {
... } |
{} |
43 | StringLiteral | Killed | 175 : 65 | ' ' |
"" |
44 | BinaryExpression | Killed | 180 : 35 | . ...|| {} |
. ...&& {} |
45 | ConditionalExpression | Killed | 180 : 35 | . ...|| {} |
|
46 | ConditionalExpression | Killed | 180 : 35 | . ...|| {} |
|
47 | Block | Survived | 184 : 62 | {
... } |
{} |
48 | IfStatement | Survived | 185 : 24 | . ... ] |
|
49 | IfStatement | Survived | 185 : 24 | . ... ] |
|
50 | Block | Survived | 185 : 48 | {
... } |
{} |
51 | StringLiteral | Survived | 191 : 35 | ' ' |
"" |
52 | StringLiteral | Survived | 192 : 35 | ' ' |
"" |
53 | Block | Killed | 201 : 28 | {
... } |
{} |
54 | ObjectLiteral | Survived | 208 : 20 | {
... } |
{} |
55 | Block | Killed | 231 : 27 | {
... } |
{} |
56 | Block | Killed | 241 : 28 | {
... } |
{} |
57 | IfStatement | Survived | 248 : 12 | . !== |
|
58 | BinaryExpression | Survived | 248 : 12 | . !== |
. === |
59 | IfStatement | Survived | 248 : 12 | . !== |
|
60 | Block | Survived | 248 : 37 | {
... } |
{} |
61 | IfStatement | Killed | 256 : 12 | . !== |
|
62 | IfStatement | Killed | 256 : 12 | . !== |
|
63 | BinaryExpression | Killed | 256 : 12 | . !== |
. === |
64 | Block | Killed | 256 : 42 | {
... } |
{} |
65 | Block | Killed | 257 : 16 | {
... } |
{} |
66 | ObjectLiteral | Survived | 258 : 45 | { } |
{} |
67 | Block | Survived | 259 : 24 | {
... } |
{} |
68 | IfStatement | Survived | 260 : 20 | . .... ' |
|
69 | IfStatement | Survived | 260 : 20 | . .... ' |
|
70 | BinaryExpression | Survived | 260 : 20 | . .... ' |
. .... ' |
71 | StringLiteral | Survived | 260 : 45 | ' ' |
"" |
72 | Block | Survived | 260 : 60 | {
... } |
{} |
73 | IfStatement | Killed | 269 : 12 | . ... . |
|
74 | IfStatement | Killed | 269 : 12 | . ... . |
|
75 | BinaryExpression | Survived | 269 : 12 | . ... . |
. ... . |
76 | Block | Survived | 269 : 56 | {
... } |
{} |
77 | Block | Killed | 271 : 15 | {
... } |
{} |
78 | Block | Killed | 272 : 16 | {
... } |
{} |
79 | ObjectLiteral | Survived | 273 : 47 | { } |
{} |
80 | Block | Survived | 274 : 24 | {
... } |
{} |
81 | IfStatement | Survived | 275 : 20 | . .... ' |
|
82 | IfStatement | Survived | 275 : 20 | . .... ' |
|
83 | BinaryExpression | Survived | 275 : 20 | . .... ' |
. .... ' |
84 | StringLiteral | Survived | 275 : 45 | ' ' |
"" |
85 | Block | Survived | 275 : 60 | {
... } |
{} |
86 | ObjectLiteral | Survived | 284 : 18 | {
... } |
{} |
87 | Block | Killed | 307 : 18 | {
... } |
{} |
88 | Block | Survived | 309 : 30 | {
... } |
{} |
89 | IfStatement | Survived | 310 : 20 | . |
|
90 | IfStatement | Survived | 310 : 20 | . |
|
91 | Block | Survived | 310 : 47 | {
... } |
{} |
92 | Block | Survived | 311 : 24 | {
... } |
{} |
93 | ObjectLiteral | Survived | 312 : 53 | {
... } |
{} |
94 | Block | Survived | 315 : 32 | {
... } |
{} |
95 | IfStatement | Survived | 316 : 28 | . .... ' |
|
96 | IfStatement | Survived | 316 : 28 | . .... ' |
|
97 | BinaryExpression | Survived | 316 : 28 | . .... ' |
. .... ' |
98 | StringLiteral | Survived | 316 : 53 | ' ' |
"" |
99 | Block | Survived | 316 : 68 | {
... } |
{} |
100 | IfStatement | Survived | 321 : 24 | . ... . |
|
101 | IfStatement | Survived | 321 : 24 | . ... . |
|
102 | Block | Survived | 321 : 56 | {
... } |
{} |
103 | StringLiteral | Survived | 322 : 95 | ', ' |
"" |
104 | BinaryExpression | Survived | 323 : 48 | . ... . |
. ... . |
105 | BinaryExpression | Survived | 324 : 51 | . ... . |
. ... . |
106 | Block | Survived | 326 : 27 | {
... } |
{} |
107 | StringLiteral | Survived | 327 : 59 | '' |
" ... !" |
108 | Block | Survived | 338 : 23 | {
... } |
{} |
109 | Block | Survived | 339 : 24 | {
... } |
{} |
110 | ObjectLiteral | Survived | 340 : 55 | { } |
{} |
111 | Block | Survived | 341 : 32 | {
... } |
{} |
112 | IfStatement | Survived | 342 : 28 | . .... ' |
|
113 | IfStatement | Survived | 342 : 28 | . .... ' |
|
114 | BinaryExpression | Survived | 342 : 28 | . .... ' |
. .... ' |
115 | StringLiteral | Survived | 342 : 53 | ' ' |
"" |
116 | Block | Survived | 342 : 68 | {
... } |
{} |
117 | IfStatement | Survived | 347 : 24 | . ... . |
|
118 | IfStatement | Survived | 347 : 24 | . ... . |
|
119 | BinaryExpression | Survived | 347 : 24 | . ... . |
. ... . |
120 | Block | Survived | 347 : 68 | {
... } |
{} |
121 | IfStatement | Survived | 352 : 24 | . . |
|
122 | IfStatement | Survived | 352 : 24 | . . |
|
123 | Block | Survived | 352 : 44 | {
... } |
{} |
124 | Block | Survived | 357 : 60 | {
... } |
{} |
125 | StringLiteral | Survived | 358 : 29 | `${ ... })` |
"" |
126 | StringLiteral | Survived | 360 : 66 | ' ... !' |
"" |
127 | BinaryExpression | Survived | 361 : 40 | . ... . |
. ... . |
128 | BinaryExpression | Survived | 362 : 43 | . ... . |
. ... . |
129 | StringLiteral | Killed | 372 : 21 | '' |
" ... !" |
130 | Block | Killed | 372 : 25 | {
... } |
{} |
131 | IfStatement | Killed | 373 : 12 | ! |
|
132 | IfStatement | Killed | 373 : 12 | ! |
|
133 | PrefixUnaryExpression | Killed | 373 : 12 | ! |
|
134 | Block | Killed | 373 : 21 | {
... } |
{} |
135 | IfStatement | Killed | 379 : 12 | . ... ) |
|
136 | IfStatement | Killed | 379 : 12 | . ... ) |
|
137 | Block | Killed | 379 : 35 | {
... } |
{} |
138 | Block | Killed | 380 : 54 | {
... } |
{} |
139 | ObjectLiteral | Survived | 383 : 28 | {
... } |
{} |
140 | ObjectLiteral | Killed | 388 : 23 | {
... } |
{} |
141 | ObjectLiteral | Survived | 398 : 20 | {
... } |
{} |
142 | Block | Killed | 413 : 35 | {
... } |
{} |
143 | ObjectLiteral | Killed | 414 : 29 | {
... } |
{} |
144 | Block | Killed | 429 : 58 | {
... } |
{} |