Issues (204)

src/Compatibility.js (17 issues)

1
/* Javascript Object Inheritance Implementation                ______  ________
2
 * (c) 2016 <[email protected]>                             __ / / __ \/  _/  _/
3
 * Licensed under MIT.                                    / // / /_/ // /_/ /
4
 * ------------------------------------------------------ \___/\____/___/__*/
5
6
JOII = typeof (JOII) !== 'undefined' ? JOII : {};
7
JOII.Compat = {};
8
9
/**
10
 * Finds and returns the name of a JOII-generated object or false if it doesn't
11
 * exist.
12
 *
13
 * @param  {Object|Function} e
14
 * @return {String|Boolean}
15
 */
16
JOII.Compat.findJOIIName = function(e, selfReferenced) {
17
    var i, r;
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
18
19
    if (typeof (e) === 'string' ||
20
        typeof (e) === 'number' ||
21
        typeof (e) === 'undefined' ||
22
        e === null
23
    ) {
24
        return false;
25
    }
26
27
    if (typeof (e.__joii__) !== 'undefined' && e.__joii__ !== null) {
28
        return e.__joii__.name;
29
    }
30
    if (typeof (e.prototype) !== 'undefined' && typeof (e.prototype.__joii__) !== 'undefined') {
31
        return e.prototype.__joii__.name;
32
    }
33
    
34
    // prevent infinite loops. Shouldn't need to go more than one deep.
35
    if (selfReferenced) {
36
        return false;
37
    }
38
39
    // Chrome / FF // IE 11+
40
    if (typeof (e.__proto__) !== 'undefined' && e.__proto__ !== null) {
41
        r = JOII.Compat.findJOIIName(e.__proto__, true);
42
        if (typeof (r) === 'string') {
43
            return r;
44
        }
45
    }
46
    
47
    if (typeof (e) === 'function') {
48
        e = e.prototype;
49
    }
50
51
    for (i in e) {
52
        if (e.hasOwnProperty(i) === false) continue;
53
        if (typeof (e[i]) === 'function' || typeof (e[i]) === 'object') {
54
            r = JOII.Compat.findJOIIName(e[i], true);
55
            if (typeof (r) === 'string') {
56
                return r;
57
            }
58
        }
59
    }
60
61
    return false;
62
};
63
64
/**
65
 * Array.indexOf implementation.
66
 *
67
 * @param  {Array} array
68
 * @param  {*}     elt
69
 * @return {Number}
70
 */
71
JOII.Compat.indexOf = function(array, elt) {
72
73
    if (typeof (array.indexOf) === 'function') {
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
74
        return array.indexOf(elt);
75
    }
76
77
    var len = array.length >>> 0,
78
        from = Number(arguments[1]) || 0;
79
80
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
81
    from = (from < 0) ? from + len : from;
82
83
    for (; from < len; from++) {
84
        if (from in array && array[from] === elt) {
85
            return from;
86
        }
87
    }
88
89
    return -1;
90
};
91
92
/**
93
 * Make a deep copy of an object.
94
 *
95
 * - original by jQuery (http://jquery.com/)
96
 */
97
JOII.Compat.extend = function() {
98
    var options, src, copy, copyIsArray = false, clone,
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
99
        target = arguments[0] || {},
100
        i = 1,
101
        length = arguments.length,
102
        deep = false;
103
    if (typeof target === "boolean") {
104
        deep = target; target = arguments[i] || {}; i++;
105
    }
106
    if (typeof target !== "object" && typeof (target) !== "function") {
107
        target = {};
108
    }
109
    for (; i < length; i++) {
110
        options = arguments[i];
111
        if (options !== null && arguments[i] !== undefined) {
112
113
            if (typeof (options.__joii__) !== 'undefined') {
114
                JOII.CreateProperty(target, '__joii__', options.__joii__);
115
            }
116
117
            for (var name in options) {
118
                // Do NOT check 'hasOwnProperty' here. The universe will implode.
119
                src = target[name];
120
                copy = options[name];
121
                if (target === copy) { continue; }
122
                if (deep && copy && (JOII.Compat.isPlainObject(copy) || (copyIsArray = JOII.Compat.isArray(copy)))) {
123
                    if (copyIsArray) {
124
                        copyIsArray = false;
125
                        clone = src && JOII.Compat.isArray(src) ? src : [];
126
                    } else {
127
                        clone = src && JOII.Compat.isPlainObject(src) ? src : {};
128
                    }
129
                    target[name] = JOII.Compat.extend(deep, clone, copy);
130
                } else if (copy !== undefined) {
131
                    target[name] = copy;
132
                }
133
            }
134
        }
135
    }
136
    return target;
137
};
138
139
140
/**
141
 * Recursively walks through a normal object, and flattens any JOII objects it finds, to prepare them for serialization
142
 *
143
 * @param  {Object} current_obj
144
 * @param  {Object} obj_base
145
 * @return {Boolean}
146
 */
147
JOII.Compat.flattenObject = function(current_obj) {
148
    var obj = null;
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
149
                    
150
    if (JOII.Compat.isArray(current_obj)) {
151
        obj = [];
152
    } else {
153
        obj = {};
154
    }
155
156
    for (var key in current_obj) {
157
        if (current_obj.hasOwnProperty(key) === false) continue;
158
159
        var currentValue = current_obj[key];
160
161
        if (typeof (currentValue) === 'object' && currentValue !== null && 'serialize' in currentValue && typeof (currentValue.serialize) === 'function') {
162
            try {
163
                obj[key] = currentValue.serialize(true);
164
165
                if (typeof(obj[key]) === 'string') {
166
                    // wasn't our serialize method. Try to deserialize back to an object to continue.
167
                    obj[key] = JSON.parse(obj[key]);
168
                }
169
            } catch (e) {
170
                // something went wrong with calling the object's serialize method. Fall back to normal crawling.
171
                obj[key] = JOII.Compat.flattenObject(currentValue);
172
            }
173
        } else if (typeof (currentValue) === 'object' && currentValue != null) {
0 ignored issues
show
It is recommended to use !== to compare with null.

Generally, it is recommended to use strict comparison whenever possible and not to rely on the weaker type-juggling comparison operator.

Read more about comparison operations.

Loading history...
174
            obj[key] = JOII.Compat.flattenObject(currentValue);
175
        } else {
176
            obj[key] = currentValue;
177
        }
178
    }
179
180
    return obj;
181
};
182
183
/**
184
 * Recursively walks through a normal object, and deserializes any JOII objects it finds,
185
 * optionally restoring to a current object while maintaining object references
186
 *
187
 * @param  {Object} current_obj
188
 * @param  {Object} obj_base
189
 * @return {Boolean}
190
 */
191
JOII.Compat.inflateObject = function(current_obj, obj_base) {
192
    var obj = obj_base || null;
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
193
    
194
    if (typeof (obj) !== 'object' || obj == null) {         
0 ignored issues
show
It is recommended to use === to compare with null.

Generally, it is recommended to use strict comparison whenever possible and not to rely on the weaker type-juggling comparison operator.

Read more about comparison operations.

Loading history...
195
        if (JOII.Compat.isArray(current_obj)) {
196
            obj = [];
197
        } else {
198
            obj = {};
199
        }
200
    }
201
202
    for (var key in current_obj) {
203
        if (current_obj.hasOwnProperty(key) === false) continue;
204
205
        var currentValue = current_obj[key];
206
        
207
        if (typeof (currentValue) === 'object' && currentValue !== null && '__joii_type' in currentValue && typeof (currentValue.__joii_type) === 'string') {
208
            var name = currentValue.__joii_type;
209
            // Check for Interface-types
210
            if (typeof (JOII.InterfaceRegistry[name]) !== 'undefined') {
211
                throw 'Cannot instantiate an interface.';
212
            }
213
            // Check for Class-types
214
            else if (typeof (JOII.ClassRegistry[name]) !== 'undefined') {
215
                var oldValue = obj[key];
216
                if (typeof (oldValue) === 'object' && oldValue !== null && '__joii__' in oldValue && typeof (oldValue.__joii__) === 'object' && oldValue.__joii__ !== null && oldValue.__joii__.name === name) {
217
                    // try to deserialize in place if the object already exists. This avoids breaking object references.
218
                    oldValue.deserialize(currentValue);
219
                } else {
220
                    obj[key] = JOII.ClassRegistry[name].deserialize(currentValue);
221
                }
222
            } else {
223
                throw 'Class ' + name + ' not currently in scope!';
224
            }
225
        } else if (typeof (currentValue) === 'object' && currentValue != null) {
0 ignored issues
show
It is recommended to use !== to compare with null.

Generally, it is recommended to use strict comparison whenever possible and not to rely on the weaker type-juggling comparison operator.

Read more about comparison operations.

Loading history...
226
            obj[key] = JOII.Compat.inflateObject(currentValue, obj[key]);
227
        } else {
228
            obj[key] = currentValue;
229
        }
230
    }
231
232
    return obj;
233
};
234
235
236
/**
237
 * Returns true if the given object is an array.
238
 *
239
 * @param  {Object} obj
240
 * @return {Boolean}
241
 */
242
JOII.Compat.isArray = function(obj) {
243
    var length = obj.length,
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
244
        type = typeof (obj);
245
246
    if (type === "function" || (typeof (window) !== 'undefined' && obj === window)) {
247
        return false;
248
    }
249
    if (obj.nodeType === 1 && length) {
250
        return true;
251
    }
252
    return Object.prototype.toString.call(obj) === '[object Array]';
253
};
254
255
/**
256
 * Returns true if the given object is a plain object (not an array).
257
 *
258
 * @param  {Object} obj
259
 * @return {Boolean}
260
 */
261
JOII.Compat.isPlainObject = function(obj) {
262
    var hasOwn = ({}).hasOwnProperty;
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
263
    if (typeof (obj) !== "object" || obj.nodeType || (typeof (window) !== 'undefined' && obj === window)) {
264
        return false;
265
    }
266
267
    return !(obj.constructor && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf"));
268
};
269
270
/**
271
 * JOII.Compat.CreateObject implementation
272
 *
273
 * @param  {Object} o
274
 * @return {Object}
275
 */
276
JOII.Compat.CreateObject = function(o) {
277
278
    if (typeof (Object.create) === 'function') {
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
279
        return Object.create(o);
280
    }
281
282
    var c = (function() {
283
        function Class() { }
284
        return function(o) {
285
            if (arguments.length != 1) {
286
                throw new Error('JOII.Compat.CreateObject implementation only accepts one parameter.');
287
            }
288
            Class.prototype = o;
289
            return new Class();
290
        };
291
    })();
292
293
    return c(o);
294
};
295
296
/**
297
 * Function.bind implementation. "bind" is part of ECMA-262, 5th edition
298
 * and therefore not available in all browsers. This polyfill is needed
299
 * to emulate the functionality of Function.bind
300
 *
301
 * @param  {Function} fn
302
 * @param  {Object}   context
303
 * @return {Function}
304
 */
305
JOII.Compat.Bind = function(fn, context) {
306
    if (typeof fn !== "function") {
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
307
        // closest thing possible to the ECMAScript 5 internal IsCallable function
308
        throw new TypeError("Function.prototype.bind - argument #1 must be a function.");
309
    }
310
311
    // return fn.bind(context);
312
313
    return function bound() {
314
        return fn.apply(context, arguments);
315
    };
316
};
317
318
/**
319
 * http://www.ietf.org/rfc/rfc4122.txt
320
 *
321
 * @return string
322
 */
323
JOII.Compat.GenerateUUID = function() {
324
    var s = [];
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
325
    var hexDigits = "0123456789abcdef";
326
    for (var i = 0; i < 36; i++) {
327
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
328
    }
329
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
330
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
331
    s[8] = s[13] = s[18] = s[23] = "-";
332
333
    return s.join("");
334
};
335
336
/**
337
 * Returns an object consisting of name, parameters and body depending on
338
 * the amount of parameters given.
339
 *
340
 * If no name is specified (argument[0] === string), a generated UUID will
341
 * take its place.
342
 *
343
 * @param  {Object} args
344
 * @return {Object}
345
 */
346
JOII.Compat.ParseArguments = function(args) {
347
    var result = { name: '', parameters: {}, body: {} };
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
348
349
    switch (args.length) {
350
        // Zero-arguments. Unlikely, but valid for classes and interfaces.
351
        case 0:
352
            result.name = JOII.Compat.GenerateUUID();
353
            break;
354
        // One argument. Name or body.
355
        case 1:
356
            if (typeof (args[0]) === 'string') {
357
                result.name = args[0];
358
            }
359
            if (typeof (args[0]) === 'object') {
360
                result.name = JOII.Compat.GenerateUUID();
361
                result.body = args[0];
362
            }
363
            break;
364
        // Two arguments: Name & Body or Parameters & Body
365
        case 2:
366
            if (typeof (args[0]) === 'string') {
367
                result.name = args[0];
368
            }
369
            if (typeof (args[0]) === 'object') {
370
                result.name = JOII.Compat.GenerateUUID();
371
                result.parameters = args[0];
372
            }
373
            result.body = args[1];
374
            break;
375
        // Three parameters: pass them all.
376
        case 3:
377
            result.name       = args[0];
378
            result.parameters = args[1];
379
            result.body = args[2];
0 ignored issues
show
Expected a 'break' statement before 'case'.
Loading history...
380
        case 4:
381
            result.name = args[0];
382
            result.parameters = args[1];
383
            result.body = args[2];
384
            result.is_static_generated = args[3];
385
    }
386
387
    // Validate the results.
388
    if (typeof (result.name) !== 'string' ||
389
        typeof (result.parameters) !== 'object' ||
390
        (typeof (result.body) !== 'object' && typeof (result.body) !== 'function')) {
391
        throw 'Invalid parameter types given. Expected: ([[[string], object], <object|function>]).';
392
    }
393
394
    return result;
395
};
396
397
/**
398
 * Some parameters can be passed as a string, object or array of both. This
399
 * function will parse the argument and return an array of actual objects.
400
 *
401
 * @param  {*} arg
402
 * @param  {Boolean} deep
403
 * @return {Object}
404
 */
405
JOII.Compat.flexibleArgumentToArray = function(arg, deep) {
406
    if (typeof (arg) === 'object' && !JOII.Compat.isArray(arg) && typeof (arg[0]) === 'undefined') {
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
407
        return [deep ? JOII.Compat.extend(true, {}, arg) : arg];
408
    } else if (typeof (arg) === 'function') {
409
        return [deep ? JOII.Compat.extend(true, {}, arg.prototype) : arg.prototype];
410
    } else if (typeof (arg) === 'object' && JOII.Compat.isArray(arg)) {
411
        var result = [];
412
        for (var i in arg) {
413
            result.push(JOII.Compat.flexibleArgumentToArray(arg[i], false)[0]);
414
        }
415
        return result;
416
    } else {
417
        throw 'Unable to read ' + typeof (arg) + '. Object, function or array expected.';
418
    }
419
};
420
421
422
JOII.Compat.canTypeBeCastTo = function(val, cast_to_type) {
423
    // InstanceOf validator (in case of interfaces & classes)
424
    if (typeof (JOII.InterfaceRegistry[cast_to_type]) !== 'undefined' ||
0 ignored issues
show
This function should enable strict mode with use strict.

Strict mode is a way to opt-in to a restricted variant of JavaScript. It eliminates some common pitfalls by being less lenient and raising more errors.

Besides, it is also used to fix certain mistakes which made it difficult for JavaScript runtimes to perform certain optimizations.

We generally recommend to only enable strict mode on the function scope and not in the global scope as that might break third-party scripts on your website.

Loading history...
425
        typeof (JOII.ClassRegistry[cast_to_type]) !== 'undefined') {
426
427
        if (JOII.Compat.findJOIIName(val) !== cast_to_type) {
428
            if (val !== null && (typeof (val.instanceOf) !== 'function' || (typeof (val) === 'object' && typeof (val.instanceOf) === 'function' && !val.instanceOf(cast_to_type)))) {
429
                return false;
430
            }
431
        }
432
    } else {
433
        // Native val validator
434
        if (typeof (JOII.EnumRegistry[cast_to_type]) !== 'undefined') {
435
            var _e = JOII.EnumRegistry[cast_to_type];
436
            if (!_e.contains(val)) {
437
                return false; // Should we really be validating that it fits inside the enum?
438
            }
439
        } else {
440
            if (typeof (val) !== cast_to_type) {
441
                return false;
442
            }
443
        }
444
    }
445
    // nothing failed, so should be compatible
446
    return true;
447
};