1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | 'use strict';
|
7 |
|
8 | const util = require('util');
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | exports.inherits = function(newClass, baseClass, options) {
|
16 | util.inherits(newClass, baseClass);
|
17 |
|
18 | options = options || {
|
19 | staticProperties: true,
|
20 | override: false,
|
21 | };
|
22 |
|
23 | if (options.staticProperties) {
|
24 | Object.keys(baseClass).forEach(function(classProp) {
|
25 | if (classProp !== 'super_' && (!newClass.hasOwnProperty(classProp) ||
|
26 | options.override)) {
|
27 | const pd = Object.getOwnPropertyDescriptor(baseClass, classProp);
|
28 | Object.defineProperty(newClass, classProp, pd);
|
29 | }
|
30 | });
|
31 | }
|
32 | };
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | exports.mixin = function(newClass, mixinClass, options) {
|
41 | if (Array.isArray(newClass._mixins)) {
|
42 | if (newClass._mixins.indexOf(mixinClass) !== -1) {
|
43 | return;
|
44 | }
|
45 | newClass._mixins.push(mixinClass);
|
46 | } else {
|
47 | newClass._mixins = [mixinClass];
|
48 | }
|
49 |
|
50 | options = options || {
|
51 | staticProperties: true,
|
52 | instanceProperties: true,
|
53 | override: false,
|
54 | proxyFunctions: false,
|
55 | };
|
56 |
|
57 | if (options.staticProperties === undefined) {
|
58 | options.staticProperties = true;
|
59 | }
|
60 |
|
61 | if (options.instanceProperties === undefined) {
|
62 | options.instanceProperties = true;
|
63 | }
|
64 |
|
65 | if (options.staticProperties) {
|
66 | mixInto(mixinClass, newClass, options);
|
67 | }
|
68 |
|
69 | if (options.instanceProperties && mixinClass.prototype) {
|
70 | mixInto(mixinClass.prototype, newClass.prototype, options);
|
71 | }
|
72 |
|
73 | return newClass;
|
74 | };
|
75 |
|
76 | function mixInto(sourceScope, targetScope, options) {
|
77 | Object.keys(sourceScope).forEach(function(propertyName) {
|
78 | const targetPropertyExists = targetScope.hasOwnProperty(propertyName);
|
79 | const sourceProperty = Object.getOwnPropertyDescriptor(sourceScope, propertyName);
|
80 | const targetProperty = targetPropertyExists && Object.getOwnPropertyDescriptor(targetScope, propertyName);
|
81 | const sourceIsFunc = typeof sourceProperty.value === 'function';
|
82 | const isFunc = targetPropertyExists && typeof targetProperty.value === 'function';
|
83 | const isDelegate = isFunc && targetProperty.value._delegate;
|
84 | const shouldOverride = options.override || !targetPropertyExists || isDelegate;
|
85 |
|
86 | if (propertyName == '_mixins') {
|
87 | mergeMixins(sourceScope._mixins, targetScope._mixins);
|
88 | return;
|
89 | }
|
90 |
|
91 | if (shouldOverride) {
|
92 | Object.defineProperty(targetScope, propertyName, sourceProperty);
|
93 | }
|
94 | });
|
95 | }
|
96 |
|
97 | function mergeMixins(source, target) {
|
98 |
|
99 | for (const ix in source) {
|
100 | const mx = source[ix];
|
101 | if (target.indexOf(mx) === -1)
|
102 | target.push(mx);
|
103 | }
|
104 | }
|