Completed
Push — master ( 5a9ffc...acd284 )
by Pieter Epeüs
25s queued 12s
created

src/validator.js   A

Complexity

Total Complexity 18
Complexity/F 1.64

Size

Lines of Code 141
Function Count 11

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 18
eloc 56
mnd 7
bc 7
fnc 11
dl 0
loc 141
rs 10
bpm 0.6363
cpm 1.6363
noi 1
c 0
b 0
f 0
1
const types = {
2
    string: String,
3
    array: Array,
4
    object: Object,
5
    number: Number,
6
    boolean: Boolean,
7
    url: URL,
8
    date: Date,
9
    function: Function,
10
};
11
12
/**
13
 * Object validator.
14
 */
15
class Validator {
16
    /**
17
     * Set the schema for the validator.
18
     *
19
     * @param {object} schema
20
     */
21
    constructor(schema) {
22
        this.schema = schema;
23
        this.errors = [];
24
    }
25
26
    /**
27
     * Validate the an array of items.
28
     *
29
     * @param {array} input
30
     *
31
     * @return {boolean}
32
     */
33
    validateAll(input) {
34
        this.errors = [];
35
        if (input.constructor !== Array || input.length < 1) {
36
            return false;
37
        }
38
39
        return input.every((item) => this.validateItem(item));
40
    }
41
42
    /**
43
     * Validate the input.
44
     *
45
     * @param {object} input
46
     *
47
     * @return {boolean}
48
     */
49
    validate(input) {
50
        this.errors = [];
51
        return this.validateItem(input);
52
    }
53
54
    /**
55
     * Validate an item.
56
     *
57
     * @param {object} item
58
     *
59
     * @return {boolean}
60
     */
61
    validateItem(item) {
62
        this.errors = Object.entries(this.schema).filter(
63
            ([fieldNameRaw, fieldType]) =>
64
                !this.filterItems(fieldNameRaw, fieldType, item)
65
        );
66
67
        return Object.entries(this.schema).every(([fieldNameRaw, fieldType]) =>
68
            this.filterItems(fieldNameRaw, fieldType, item)
69
        );
70
    }
71
72
    filterItems(fieldNameRaw, fieldType, item) {
73
        if (!item) {
74
            return false;
75
        }
76
77
        let fieldName = fieldNameRaw;
78
79
        if (fieldNameRaw.substr(0, 1) === '?') {
80
            fieldName = fieldNameRaw.substr(1);
81
82
            if (
83
                !Object.prototype.hasOwnProperty.call(item, fieldName) ||
84
                item[fieldName] === null ||
85
                item[fieldName] === undefined
86
            ) {
87
                return true;
88
            }
89
        }
90
91
        const value = item[fieldName];
92
93
        if (value === null || value === undefined) {
94
            return false;
95
        }
96
97
        if (typeof fieldType !== 'string' && value.constructor === fieldType) {
98
            return true;
99
        }
100
101
        if (!types.hasOwnProperty(fieldType)) {
102
            const validationMethod = `validate${value.constructor.name}`;
103
104
            return this[validationMethod](value, fieldType);
105
        }
106
107
        const type = types[fieldType];
108
109
        return value.constructor === type;
110
    }
111
112
    /**
113
     * Validate an array
114
     *
115
     * @param {mixed} value
116
     * @param {string} fieldType
117
     *
118
     * @return {boolean}
119
     */
120
    validateArray(value, fieldType) {
121
        return value.every((item) => this.validateObject(item, fieldType));
122
    }
123
124
    /**
125
     * Validate an object
126
     *
127
     * @param {mixed} value
128
     * @param {string} fieldType
129
     *
130
     * @return {boolean}
131
     */
132
    validateObject(value, fieldType) {
133
        const validator = new Validator(fieldType);
134
135
        return validator.validate(value);
136
    }
137
}
138
139
module.exports = {
140
    Validator,
141
    types,
142
};
143