-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathWireProxy.js
205 lines (181 loc) · 5.74 KB
/
WireProxy.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/** @license MIT License (c) copyright B Cavalier & J Hann */
/**
* Licensed under the MIT License at:
* http://www.opensource.org/licenses/mit-license.php
*/
(function(define){ 'use strict';
define(function(require) {
var object, array;
object = require('./object');
array = require('./array');
/**
* A base proxy for all components that wire creates. It allows wire's
* internals and plugins to work with components using a standard interface.
* WireProxy instances may be extended to specialize the behavior of the
* interface for a particular type of component. For example, there is a
* specialized version for DOM Nodes.
* @param {*} target value to be proxied
* @constructor
*/
function WireProxy(target) {
// read-only target
Object.defineProperty(this, 'target', { value: target });
}
WireProxy.prototype = {
/**
* Get the value of the named property. Sub-types should
* override to get properties from their targets in whatever
* specialized way is necessary.
* @param {string} property
* @returns {*} the value or undefined
*/
get: function (property) {
return this.target[property];
},
/**
* Set the value of the named property. Sub-types should
* override to set properties on their targets in whatever
* specialized way is necessary.
* @param {string} property
* @param {*} value
* @returns {*}
*/
set: function (property, value) {
this.target[property] = value;
return value;
},
/**
* Invoke the method, with the supplied args, on the proxy's
* target. Sub-types should override to invoke methods their
* targets in whatever specialized way is necessary.
* @param {string|function} method name of method to invoke or
* a function to call using proxy's target as the thisArg
* @param {array} args arguments to pass to method
* @returns {*} the method's return value
*/
invoke: function (method, args) {
var target = this.target;
if (typeof method === 'string') {
method = target[method];
}
return method.apply(target, array.fromArguments(args));
},
/**
* Add an aspect to the proxy's target. Sub-types should
* override to add aspects in whatever specialized way is
* necessary.
* @param {String|Array|RegExp|Function} pointcut
* expression matching methods to be advised
* @param {Object} aspect aspect to add
* @returns {{remove:function}} object with remove() that
* will remove the aspect.
*/
advise: function(pointcut, aspect) {
/*jshint unused:false*/
throw new TypeError('Advice not supported on component type: ' + this.target);
},
/**
* Destroy the proxy's target. Sub-types should override
* to destroy their targets in whatever specialized way is
* necessary.
*/
destroy: function() {},
/**
* Attempt to clone this proxy's target. Sub-types should
* override to clone their targets in whatever specialized
* way is necessary.
* @param {object|array|function} thing thing to clone
* @param {object} options
* @param {boolean} options.deep if true and thing is an Array, try to deep clone its contents
* @param {boolean} options.inherited if true and thing is an object, clone inherited and own properties.
* @returns {*}
*/
clone: function (options) {
// don't try to clone a primitive
var target = this.target;
if (typeof target == 'function') {
// cloneThing doesn't clone functions, so clone here:
return target.bind();
} else if (typeof target != 'object') {
return target;
}
return cloneThing(target, options || {});
}
};
WireProxy.isProxy = isProxy;
WireProxy.getTarget = getTarget;
WireProxy.extend = extendProxy;
return WireProxy;
/**
* Returns a new WireProxy, whose prototype is proxy, with extensions
* as own properties. This is the "official" way to extend the functionality
* of an existing WireProxy.
* @param {WireProxy} proxy proxy to extend
* @param extensions
* @returns {*}
*/
function extendProxy(proxy, extensions) {
if(!isProxy(proxy)) {
throw new Error('Cannot extend non-WireProxy');
}
return object.extend(proxy, extensions);
}
/**
* Returns true if it is a WireProxy
* @param {*} it
* @returns {boolean}
*/
function isProxy(it) {
return it instanceof WireProxy;
}
/**
* If it is a WireProxy (see isProxy), returns it's target. Otherwise,
* returns it;
* @param {*} it
* @returns {*}
*/
function getTarget(it) {
return isProxy(it) ? it.target : it;
}
/**
* Try to clone thing, which can be an object, Array, or Function
* @param {object|array|function} thing thing to clone
* @param {object} options
* @param {boolean} options.deep if true and thing is an Array, try to deep clone its contents
* @param {boolean} options.inherited if true and thing is an object, clone inherited and own properties.
* @returns {array|object|function} cloned thing
*/
function cloneThing (thing, options) {
var deep, inherited, clone, prop;
deep = options.deep;
inherited = options.inherited;
// Note: this filters out primitive properties and methods
if (typeof thing != 'object') {
return thing;
}
else if (thing instanceof Date) {
return new Date(thing.getTime());
}
else if (thing instanceof RegExp) {
return new RegExp(thing);
}
else if (Array.isArray(thing)) {
return deep
? thing.map(function (i) { return cloneThing(i, options); })
: thing.slice();
}
else {
clone = thing.constructor ? new thing.constructor() : {};
for (prop in thing) {
if (inherited || object.hasOwn(thing, prop)) {
clone[prop] = deep
? cloneThing(thing[prop], options)
: thing[prop];
}
}
return clone;
}
}
});
})(typeof define == 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }
);