Issues (204)

src/ClassBuilder.js (50 issues)

1
/* Javascript Object Inheritance Implementation                ______  ________
2
 * (c) 2016 <[email protected]>                             __ / / __ \/  _/  _/
3
 * Licensed under MIT.                                    / // / /_/ // /_/ /
4
 * ------------------------------------------------------ \___/\____/___/__*/
5
6
'use strict';
7
8
    JOII = typeof (JOII) !== 'undefined' ? JOII : {};
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
9
    JOII.ClassRegistry = {};
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
10
11
    /**
12
     * The ClassBuilder is responsible for creating a class definition based
13
     * on the given parameters and body. We use the PrototypeBuilder to create
14
     * a uniform prototype based on our own defined class body and the
15
     * prototypes of inherited definitions.
16
     *
17
     * The resulting function will be the class definition which creates its
18
     * own new 'scope' each time it's instantiated.
19
     *
20
     * @param string name
21
     * @param object parameters
22
     * @param object body
23
     * @return function
24
     */
25
    JOII.ClassBuilder = function() {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
26
        var args                        = JOII.Compat.ParseArguments(arguments),
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
27
            name                        = args.name,
28
            parameters                  = args.parameters,
29
            body                        = args.body,
30
            is_static_generated         = args.is_static_generated === true;
31
        
32
        function static_scope_in() {
33
            // If 'this.__joii__' is not available, that would indicate that
34
            // we've been executed like a function rather than being instantiated.
35
            if (typeof (this) === 'undefined' || typeof (this.__joii__) === 'undefined') {
36
                // If the method __call exists, execute it and return its result.
37
38
                return definition.apply(undefined, arguments);
39
            }
40
41
            return new definition();
42
        }
43
        /**
44
         * Defines the class definition. This is the function that is executed
45
         * when the class is instantiated or executed. The function will relay
46
         * execution to the __construct or __call method, depending whether the
47
         * class was called as a function or instantiated using the 'new'
48
         * keyword.
49
         *
50
         * @return object The outer (public) class scope.
51
         */
52
        function definition() {
0 ignored issues
show
'definition' was used before it was defined.
Loading history...
53
54
            var func_in         = function() { };
55
            func_in.prototype   = this;
56
            var scope_in_obj    = new func_in();
57
            
58
59
            // Create an inner and outer scope. The inner scope refers to the
60
            // 'this' variable, where the outer scope contains references to
61
            // all objects and functions accessible from the outside.
62
            var scope_in = generateInnerScope(this, arguments, scope_in_obj, false);
63
            
64
            // for __call implementations
65
            if (typeof (this) === 'undefined' || typeof (this.__joii__) === 'undefined' || typeof (scope_in) !== 'object' || typeof (scope_in.__joii__) === 'undefined') {
66
                return scope_in;
67
            }
68
69
            
70
71
            
72
            var scope_out = generateOuterScope(this, scope_in);
73
            
74
            // need to link the inner and outer scopes before calling constructors
75
            linkAPI(scope_in, scope_out);
76
            
77
78
            // apply meta traits
79
            JOII.callMetaMixin('beforeNew', scope_in, scope_out);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
80
81
            for (var meta_index in scope_in.__joii__.metadata) {
82
                if (scope_in.__joii__.metadata.hasOwnProperty(meta_index) === false) continue;
83
                var meta = scope_in.__joii__.metadata[meta_index];
84
        
85
                JOII.callMetaMixin('onNew', scope_in, scope_out, meta);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
86
            }
87
    
88
            JOII.callMetaMixin('afterNew', scope_in, scope_out);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
89
90
91
            callConstructors(scope_in, arguments);
92
93
            return scope_out;
94
        }
95
96
        function callConstructors(scope_in, args)
0 ignored issues
show
'callConstructors' was used before it was defined.
Loading history...
97
        {
98
            // Does the class defintion have a constructor? If so, run it.
99
            for (var c in JOII.Config.constructors) {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
100
                if (JOII.Config.constructors.hasOwnProperty(c)) {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
101
                    var cc = JOII.Config.constructors[c];
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
102
                    if (typeof (scope_in[cc]) === 'function') {
103
                        scope_in[cc].apply(scope_in, args);
104
                        break;
105
                    }
106
                }
107
            }
108
            
109
            // deserialize data
110
            if (args.length == 1 && typeof args[0] == 'object' && '__joii_deserialize_object' in args[0]) {
111
                scope_in.deserialize(args[0].data);
112
            }
113
        }
114
115
        function linkAPI(scope_in, scope_out)
0 ignored issues
show
'linkAPI' was used before it was defined.
Loading history...
116
        {
117
            // Create a reference to the outer scope for use in fluid interfacing.
118
            scope_in.__api__ = scope_out;
119
120
            // Apply the API object to inherited classes to keep the super() functionality working no matter how deep
121
            // the inheritance-chain goes.
122
            // This feels really 'hacky' in my opinion, but it fixes issue #19 and doesn't break any other test.
123
            // As far as I can tell, there's no real performance impact on this, although I'm running this on a beast
124
            // of a computer. If anyone has a more elegant solution, a pull-request would be much appreciated!
125
            if (typeof scope_in.__joii__.parent !== 'undefined') {
126
                var current = scope_in.__joii__.parent;
127
                while (typeof current !== 'undefined') {
128
                    current.__api__ = scope_out;
129
                    current = current.__joii__.parent;
130
                }
131
            }
132
        }
133
134
        function generateInnerScope(scope, args, base_object, is_static_generated) {
0 ignored issues
show
'generateInnerScope' was used before it was defined.
Loading history...
135
            var scope_in = base_object || {};
136
137
            is_static_generated = is_static_generated || false;
138
139
            // Create a deep copy of the inner scope because we need to
140
            // dereference object-type properties. If we don't do this, object-
141
            // types are treated statically throughout all instances.
142
            scope_in = JOII.Compat.extend(true, {}, scope_in);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
143
144
            if (typeof scope !== 'undefined') {
145
                JOII.CreateProperty(scope_in, '__joii__', (scope.__joii__));
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
146
            }
147
148
            if (typeof scope !== 'undefined' && typeof (scope_in.__joii__) === 'object') {
149
                // Can we be instantiated?
150
                if (scope_in.__joii__.is_abstract === true) {
151
                    throw 'An abstract class cannot be instantiated.';
152
                }
153
                if (!is_static_generated && scope_in.__joii__.is_static === true) {
154
                    throw 'A static class cannot be instantiated.';
155
                }
156
            }
157
158
            // If 'this.__joii__' is not available, that would indicate that
159
            // we've been executed like a function rather than being instantiated.
160
            if (typeof (scope) === 'undefined' || typeof (scope.__joii__) === 'undefined') {
161
                // If the method __call exists, execute it and return its result.
162
163
                if (typeof (static_scope_in) !== 'undefined')
164
                {
165
                    for (var c in JOII.Config.callables) {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
166
                        if (JOII.Config.callables.hasOwnProperty(c)) {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
167
                            if (typeof (static_scope_in[JOII.Config.callables[c]]) === 'function') {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
168
                                var result = static_scope_in[JOII.Config.callables[c]].apply(body, args);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
169
                                if (result === body) {
170
                                    throw JOII.Config.callables[c] + ' cannot return itself.';
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
171
                                }
172
                                return result;
173
                            }
174
                        }
175
                    }
176
                }
177
                throw 'This class cannot be called as a function because it\'s lacking the __call method.';
178
            }
179
180
181
182
            // Are we attempting to instantiate an abstract class?
183
            if (scope.__joii__.is_abstract) {
184
                throw 'Cannot instantiate abstract class ' + scope.__joii__.name;
185
            }
186
187
188
            return scope_in;
189
190
        }
191
192
        function generateOuterScope(scope, scope_in, base_object) {
0 ignored issues
show
'generateOuterScope' was used before it was defined.
Loading history...
193
            var scope_out = base_object || {};
194
            
195
            if (typeof scope !== 'undefined' && typeof (scope.__joii__) === 'object') {
196
                
197
                JOII.CreateProperty(scope_out, '__joii__', (scope.__joii__));
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
198
            
199
                // Can we be instantiated?
200
                if (scope_out.__joii__.is_abstract === true) {
201
                    throw 'An abstract class cannot be instantiated.';
202
                }
203
204
                // The outside scope.
205
                for (var i in scope) {
206
                    var meta = scope_in.__joii__.metadata[i];
207
208
                    if (meta && 'overloads' in meta) {
209
                        for (var fn_meta in meta.overloads) {
210
                            // Test missing abstract implementations...
211
                            if (meta.overloads[fn_meta] && meta.overloads[fn_meta].is_abstract === true) {
212
                                throw 'Missing abstract member implementation of ' + i + '(' + meta.overloads[fn_meta].parameters.join(', ') + ')';
213
                            }
214
                        }
215
                    } else if (meta && meta.is_abstract === true) {
216
                        throw 'Missing abstract member implementation of "' + i + '".';
217
                    }
218
                }
219
            }
220
221
            bindPublicMethods(scope_in, scope_out);
222
223
            return scope_out;
224
        }
225
226
        function bindPublicMethods(from_obj, to_obj)
0 ignored issues
show
'bindPublicMethods' was used before it was defined.
Loading history...
227
        {
228
            // The outside scope.
229
            for (var i in from_obj) {
230
                var meta = from_obj.__joii__.metadata[i];
231
                
232
                // Only allow public functions in the outside scope.
233
                if (typeof (from_obj[i]) === 'function' && (typeof (meta) === 'undefined' || meta.visibility === 'public') && (i !== '__call')) {
234
                    to_obj[i] = JOII.Compat.Bind(from_obj[i], from_obj);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
235
                }
236
            }
237
        }
238
239
240
        if (typeof (body) == 'function') {
241
            body = body(static_scope_in);
242
        }
243
        
244
        if (typeof (body) != 'object') {
245
            throw 'Invalid parameter types given. Expected: ([[[string], object], <object|function>]).';
246
        }
247
248
        
249
250
        // Apply to prototype to the instantiator to allow extending the
251
        // class definition upon other definitions without instantiation.
252
        definition.prototype = JOII.PrototypeBuilder(name, parameters, body, false, is_static_generated);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
253
        
254
255
256
        // Apply constants to the definition
257
        for (var i in definition.prototype.__joii__.constants) {
258
            JOII.CreateProperty(definition, i, definition.prototype.__joii__.constants[i], false);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
259
        }
260
261
        // Does the class implement an enumerator?
262
        if (typeof (parameters['enum']) === 'string') {
263
            var e = JOII.EnumBuilder(parameters['enum'], definition);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
264
            if (parameters.expose_enum === true) {
265
                var g = typeof window === 'object' ? window : global;
266
                if (typeof (g[parameters['enum']]) !== 'undefined') {
267
                    throw 'Cannot expose Enum "' + parameters['enum'] + '" becase it already exists in the global scope.';
268
                }
269
                g[parameters['enum']] = e;
270
            }
271
        }
272
273
        // Override toString to return a class symbol.
274
        var n = arguments[0];
275
        definition.toString = function() {
276
            if (typeof (n) === 'string') {
277
                return '[class ' + n + ']';
278
            }
279
            return '[class Class]';
280
        };
281
282
        // Store defined interfaces in the metadata.
283
        definition.prototype.__joii__.interfaces = parameters['implements'];
284
285
        // TODO performance can be increased here by storing the parsed
286
        //      interfaces in the 'interfaces' array in __joii__.
287
288
        // Recursive function for retrieving a list of interfaces from the
289
        // current class and the rest of the inheritance tree.
290
        bindGetInterfaces(definition.prototype.__joii__);
291
292
293
        function bindGetInterfaces(joii)
0 ignored issues
show
'bindGetInterfaces' was used before it was defined.
Loading history...
294
        {
295
            
296
            // Recursive function for retrieving a list of interfaces from the
297
            // current class and the rest of the inheritance tree.
298
            joii.getInterfaces = JOII.Compat.Bind(function() {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
299
                var interfaces = [],
300
                    getRealInterface = JOII.Compat.Bind(function(i) {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
301
                        if (typeof (i) === 'function') {
302
                            return i;
303
                        } else if (typeof (i) === 'string') {
304
                            if (typeof (JOII.InterfaceRegistry[i]) === 'undefined') {
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
305
                                throw 'Interface "' + i + '" does not exist.';
306
                            }
307
                            return JOII.InterfaceRegistry[i];
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
308
                        }
309
                    }, this);
310
311
                // Fetch interfaces from the parent list - if they exist.
312
                if (typeof (this.parent) !== 'undefined' && typeof (this.parent.__joii__) !== 'undefined') {
313
                    interfaces = this.parent.__joii__.getInterfaces();
314
                }
315
316
                if (typeof (this.interfaces) !== 'undefined') {
317
                    if (typeof (this.interfaces) === 'object') {
318
                        for (var i in this.interfaces) {
319
                            if (!this.interfaces.hasOwnProperty(i)) {
320
                                continue;
321
                            }
322
                            interfaces.push(getRealInterface(this.interfaces[i]));
323
                        }
324
                    } else {
325
                        interfaces.push(getRealInterface(this.interfaces));
326
                    }
327
                }
328
329
                return interfaces;
330
            }, joii);
331
        }
332
333
        // If any interfaces are implemented in this class, validate them
334
        // immediately rather than doing so during instantiation. If the
335
        // class is declared abstract, the validation is skipped.
336
        if (parameters.abstract !== true) {
337
            var interfaces = definition.prototype.__joii__.getInterfaces();
338
            for (var ii in interfaces) {
339
                if (interfaces.hasOwnProperty(ii) && typeof (interfaces[ii]) === 'function') {
340
                    interfaces[ii](definition);
341
                }
342
            }
343
        }
344
345
        
346
        if (parameters['static'] !== true && !is_static_generated) {
347
348
            // check to make sure serialize doesn't exist yet, or if it does - it's capable of being overloaded without breaking BC
349
            if ((!('serialize' in definition.prototype.__joii__.metadata)) || (('overloads' in definition.prototype.__joii__.metadata['serialize']) && (definition.prototype.__joii__.metadata['serialize']['overloads'][0].parameters.length > 0 || definition.prototype.__joii__.metadata['serialize']['overloads'].length > 1))) {
350
                
351
                /**
352
                 * Serializes all serializable properties of an object. Public members are serializable by default.
353
                 *
354
                 * @return {String}
355
                 */
356
                var generated_fn = function() {
357
                    return JSON.stringify(this.serialize(true));
358
                };
359
                // uses an inheritance style add, so it won't overwrite custom functions with the same signature
360
                var serialize_meta = JOII.ParseClassProperty('public function serialize()');
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
361
                JOII.addFunctionToPrototype(definition.prototype, serialize_meta, generated_fn, true);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
362
363
                
364
                /**
365
                 * Serializes all serializable properties of an object. Public members are serializable by default.
366
                 *
367
                 * @return {Object}
368
                 */
369
                var generated_fn = function(bool_return_object) {
0 ignored issues
show
It seems like generated_fn was already defined.
Loading history...
370
                    var obj = { __joii_type: this.__joii__.name };
371
372
                    for (var key in this.__joii__.metadata) {
373
                        var val = this.__joii__.metadata[key];
374
375
                        if (val.serializable) {
376
                            
377
                            var getter_name = JOII.GenerateGetterName(val);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
378
                            var currentValue = null;
379
                            if (typeof (this[getter_name]) === 'function') {
380
                                // use getter if it exists. This allows custom getters to translate the data properly if needed.
381
                                currentValue = this[getter_name]();
382
                            } else {
383
                                currentValue = this[val.name];
384
                            }
385
386
                            if (!val.is_enum && typeof (currentValue) === 'object' && currentValue !== null) {
387
                                if ('serialize' in currentValue) {
388
                                    obj[val.name] = currentValue.serialize(true);
389
                                } else {
390
                                    obj[val.name] = JOII.Compat.flattenObject(currentValue);
0 ignored issues
show
JOII does not seem to be defined.
Loading history...
There were too many errors found in this file; checking aborted after 61%.

If JSHint finds too many errors in a file, it aborts checking altogether because it suspects a configuration issue.

Further Reading:

Loading history...
391
                                }
392
                            } else {
393
                                obj[val.name] = currentValue;
394
                            }
395
                        }
396
                    }
397
398
                    return obj;
399
                };
400
                // uses an inheritance style add, so it won't overwrite custom functions with the same signature
401
                var serialize_meta = JOII.ParseClassProperty('public function serialize(boolean)');
0 ignored issues
show
It seems like serialize_meta was already defined.
Loading history...
402
                JOII.addFunctionToPrototype(definition.prototype, serialize_meta, generated_fn, true);
403
            }
404
405
406
407
            // check to make sure deserialize doesn't exist yet, or if it does - it's capable of being overloaded without breaking BC
408
            if ((!('deserialize' in definition.prototype.__joii__.metadata)) || (('overloads' in definition.prototype.__joii__.metadata['deserialize']) && (definition.prototype.__joii__.metadata['deserialize']['overloads'][0].parameters.length > 0 || definition.prototype.__joii__.metadata['deserialize']['overloads'].length > 1))) {
409
                /**
410
                 * Deserializes a class (called on an object instance to populate it)
411
                 *
412
                 * @param {String}
413
                 */
414
                var generated_fn = function(json) {
0 ignored issues
show
It seems like generated_fn was already defined.
Loading history...
415
                    this.deserialize(JSON.parse(json));
416
                };
417
                // uses an inheritance style add, so it won't overwrite custom functions with the same signature
418
                var deserialize_meta = JOII.ParseClassProperty('public function deserialize(string)');
419
                JOII.addFunctionToPrototype(definition.prototype, deserialize_meta, generated_fn, true);
420
                
421
                /**
422
                 * Deserializes a class (called on an object instance to populate it)
423
                 *
424
                 * @param {Object}
425
                 */
426
                generated_fn = function(obj) {
427
                    for (var key in (this.__joii__.metadata)) {
428
                        var val = this.__joii__.metadata[key];
429
430
                        if (val.serializable) {
431
                            if (val.name in obj && typeof (obj[val.name]) != 'function') {
432
                                var setter_name = JOII.GenerateSetterName(val);
433
                                var getter_name = JOII.GenerateGetterName(val);
434
435
436
                                if (typeof (obj[val.name]) === 'object' && obj[val.name] !== null && '__joii_type' in (obj[val.name])) {
437
                                    var name = obj[val.name].__joii_type;
438
                                    // Check for Interface-types
439
                                    if (typeof (JOII.InterfaceRegistry[name]) !== 'undefined') {
440
                                        throw 'Cannot instantiate an interface.';
441
                                    }
442
                                    // Check for Class-types
443
                                    else if (typeof (JOII.ClassRegistry[name]) !== 'undefined') {
444
                                        
445
                                        var currentValue = null;
446
                                        if (typeof (this[getter_name]) === 'function') {
447
                                            // use getter if it exists. This allows custom getters to translate the data properly if needed.
448
                                            currentValue = this[getter_name]();
449
                                        } else {
450
                                            currentValue = this[val.name];
451
                                        }
452
453
                                        if (typeof (currentValue) === 'object' && currentValue !== null && currentValue.__joii__.name === name) {
454
                                            // try to deserialize in place if the object already exists. This avoids breaking object references.
455
                                            currentValue.deserialize(obj[val.name]);
456
                                        } else {
457
                                            if (typeof (this[setter_name]) === 'function') {
458
                                                // use setter if it exists. This allows custom setters to translate the data properly.
459
                                                this[setter_name](JOII.ClassRegistry[name].deserialize(obj[val.name]));
460
                                            } else {
461
                                                // need to set directly
462
                                                this[val.name] = JOII.ClassRegistry[name].deserialize(obj[val.name]);
463
                                            }
464
                                        }
465
                                    } else {
466
                                        throw 'Class ' + name + ' not currently in scope!';
467
                                    }
468
                                } else if (typeof (obj[val.name]) === 'object' && obj[val.name] !== null) {
469
470
                                    var currentValue = null;
0 ignored issues
show
It seems like currentValue was already defined.
Loading history...
471
                                    if (typeof (this[getter_name]) === 'function') {
472
                                        // use getter if it exists. This allows custom getters to translate the data properly if needed.
473
                                        currentValue = this[getter_name]();
474
                                    } else {
475
                                        currentValue = this[val.name];
476
                                    }
477
478
                                    // normal object. Crawl through it to find JOII objects.
479
                                    var new_val = JOII.Compat.inflateObject(obj[val.name], currentValue);
480
481
                                    if (typeof (this[setter_name]) === 'function') {
482
                                        // use setter if it exists. This allows custom setters to translate the data properly.
483
                                        this[setter_name](new_val);
484
                                    } else {
485
                                        this[val.name] = new_val;
486
                                    }
487
                                } else {
488
                                    if (typeof (this[setter_name]) === 'function') {
489
                                        // use setter if it exists. This allows custom setters to translate the data properly.
490
                                        this[setter_name](obj[val.name]);
491
                                    } else {
492
                                        this[val.name] = obj[val.name];
493
                                    }
494
                                }
495
                            }
496
                        }
497
                    }
498
                };
499
                // uses an inheritance style add, so it won't overwrite custom functions with the same signature
500
                deserialize_meta = JOII.ParseClassProperty('public function deserialize(object)');
501
                JOII.addFunctionToPrototype(definition.prototype, deserialize_meta, generated_fn, true);
502
503
            };
0 ignored issues
show
This semicolons seems to be unnecessary.
Loading history...
504
505
        }
506
507
508
509
        
510
        // if it's not a static class, generate it's static backing field
511
        if (!is_static_generated && typeof (parameters['enum']) !== 'string') {
512
            
513
            var __in_joii_static_class_constructor = false;
514
515
            function staticDefinition() {
0 ignored issues
show
It is not recommended to place function declarations in blocks.

Although, declaring functions inside blocks will not necessarily lead to runtime errors, the code might not behave as you expect it as declarations are automatically declared in the top-most scope (see ECMAScript specification).

For code such as:

function someFunction() {
    function anotherFunction() { }
}

it is recommended to make one of these two fixes:

1. Move Function Declaration outside of the block

function someFunction() { }
function anotherFunction() { }

2. Use a Function Expression

function someFunction() {
    var anotherFunction = function() { };
}
Loading history...
516
517
                var func_in         = function() { };
518
                func_in.prototype   = this;
519
                var scope_in_obj    = new func_in();
520
521
                static_scope_in.prototype = definition;
522
523
                // Create an inner static scope, for private/protected members                
524
                var scope_in = generateInnerScope(this, [], scope_in_obj, true);
525
            
526
                // Create the static field, and copy it into the object we created before.
527
                // Need to copy it this way, so that the object reference is still the same, 
528
                // since we may have passed it into the optional user function which generates the body
529
                static_scope_in = JOII.Compat.extend(true, static_scope_in, scope_in);
0 ignored issues
show
Reassignment of 'static_scope_in', which is is a function. Use 'var' or 'let' to declare bindings that may change.
Loading history...
530
                
531
                // bind any public static members to the outside class
532
                //bindPublicMethods(static_scope_in, definition);
533
534
                definition = generateOuterScope(static_scope_in, static_scope_in, definition);
0 ignored issues
show
Reassignment of 'definition', which is is a function. Use 'var' or 'let' to declare bindings that may change.
Loading history...
535
                
536
                // need to link the inner and outer scopes before calling constructors
537
                linkAPI(static_scope_in, definition);
538
                
539
                // static constructors can't have parameters
540
                callConstructors(static_scope_in, []);
541
                
542
                return static_scope_in;
543
            }
544
            
545
            __in_joii_static_class_constructor = true;
546
547
            // Apply to prototype to the instantiator to allow extending the
548
            // class definition upon other definitions without instantiation.
549
            staticDefinition.prototype = JOII.PrototypeBuilder(name, parameters, body, false, true);
550
            
551
            // Store defined interfaces in the metadata.
552
            staticDefinition.prototype.__joii__.interfaces = parameters['implements'];
553
554
            bindGetInterfaces(staticDefinition.prototype.__joii__);
555
            
556
            // If any interfaces are implemented in this class, validate them
557
            // immediately rather than doing so during instantiation. If the
558
            // class is declared abstract, the validation is skipped.
559
            if (parameters.abstract !== true) {
560
                var interfaces = staticDefinition.prototype.__joii__.getInterfaces();
0 ignored issues
show
It seems like interfaces was already defined.
Loading history...
561
                for (var ii in interfaces) {
0 ignored issues
show
It seems like ii was already defined.
Loading history...
562
                    if (interfaces.hasOwnProperty(ii) && typeof (interfaces[ii]) === 'function') {
563
                        interfaces[ii](staticDefinition);
564
                    }
565
                }
566
            }
567
568
            /**
569
             * Deserializes a class (called as a static method - instantiates a new object and populates it)
570
             *
571
             * @param {String}
572
             */
573
            var generated_fn = function(json) {
0 ignored issues
show
It seems like generated_fn was already defined.
Loading history...
574
                return this.deserialize(JSON.parse(json));
575
            };
576
            // uses an inheritance style add, so it won't overwrite custom functions with the same signature
577
            var deserialize_meta = JOII.ParseClassProperty('public static function deserialize(string)');
0 ignored issues
show
It seems like deserialize_meta was already defined.
Loading history...
578
            JOII.addFunctionToPrototype(staticDefinition.prototype, deserialize_meta, generated_fn, true);
579
580
            
581
            /**
582
             * Deserializes a class (called as a static method - instantiates a new object and populates it)
583
             *
584
             * @param {Object}
585
             */
586
            generated_fn = function(obj) {
587
                var deserialize_object = {
588
                    '__joii_deserialize_object': true,
589
                    'data': obj
590
                };
591
                return new definition(deserialize_object);
592
            };
593
            // uses an inheritance style add, so it won't overwrite custom functions with the same signature
594
            deserialize_meta = JOII.ParseClassProperty('public static function deserialize(object)');
595
            JOII.addFunctionToPrototype(staticDefinition.prototype, deserialize_meta, generated_fn, true);
596
597
598
            /**
599
             * Gets the current static scope
600
             *
601
             * @param {String}
602
             */
603
            /*
604
            var generated_fn = function() {
605
                return static_scope_in;
606
            };
607
            // uses an inheritance style add, so it won't overwrite custom functions with the same signature
608
            var deserialize_meta = JOII.ParseClassProperty('private function getStatic()');
609
            JOII.addFunctionToPrototype(definition.prototype, deserialize_meta, generated_fn, true);
610
            */
611
612
            // create an object for the static members, and store a reference to it
613
            inner_static_objects[name] = new staticDefinition();
614
            
615
            
616
            definition.__joii__.prototype = staticDefinition.prototype;
617
            
618
619
        }
620
621
622
        
623
        
624
        // Register the class by the given name to make it usable as a type
625
        // inside property declarations.
626
        if (typeof (JOII.ClassRegistry[name]) !== 'undefined') {
627
            throw 'Another class named "' + name + '" already exists.';
628
        }
629
        JOII.ClassRegistry[name] = definition;
630
631
632
633
        definition.prototype = JOII.Compat.extend(true, {}, definition.prototype);
634
635
        return definition;
636
    };
637