Included support for property definitions
This commit is contained in:
Родитель
9dc3aa4ac3
Коммит
aa6b9e6b54
|
@ -1,5 +1,5 @@
|
|||
(function(){function m(){function u(){return null}function l(a){return a?"object"===typeof a||"function"===typeof a:!1}function n(a){if(null!==a&&!l(a))throw new TypeError("Object prototype may only be an Object or null: "+a);}function v(a,c,A){function k(){}if(!l(a)||!l(c))throw new TypeError("Cannot create proxy with a non-object as target or handler");var g=c;c={get:null,set:null,apply:null,construct:null};for(var h in g){if(!(h in c))throw new TypeError("Proxy polyfill does not support trap '"+h+"'");c[h]=
|
||||
g[h]}"function"===typeof g&&(c.apply=g.apply.bind(g));g=B(a);var p=!1,q=!1;if("function"===typeof a){var e=function(){var b=this&&this.constructor===e,d=Array.prototype.slice.call(arguments);k(b?"construct":"apply");return b&&c.construct?c.construct.call(this,a,d):!b&&c.apply?c.apply(a,this,d):b?(d.unshift(a),new (a.bind.apply(a,d))):a.apply(this,d)};p=!0}else a instanceof Array?(e=[],q=!0):e=w||null!==g?C(g):{};var x=c.get?function(b){k("get");return c.get(this,b,e)}:function(b){k("get");return this[b]},
|
||||
D=c.set?function(b,d){k("set");c.set(this,b,d,e)}:function(b,d){k("set");this[b]=d},y={};f.getOwnPropertyNames(a).forEach(function(b){if(!((p||q)&&b in e)){var d=f.getOwnPropertyDescriptor(a,b);f.defineProperty(e,b,{enumerable:!!d.enumerable,get:x.bind(a,b),set:D.bind(a,b)});y[b]=!0}});h=!0;if(p||q){var E=f.setPrototypeOf||([].__proto__===Array.prototype?function(b,d){n(d);b.__proto__=d;return b}:u);g&&E(e,g)||(h=!1)}if(c.get||!h)for(var r in a)y[r]||f.defineProperty(e,r,{get:x.bind(a,r)});f.seal(a);
|
||||
f.seal(e);return A?{proxy:e,revoke:function(){a=null;k=function(b){throw new TypeError("Cannot perform '"+b+"' on a proxy that has been revoked");}}}:e}var f=Object,w=!!f.create||!({__proto__:null}instanceof f),C=f.create||(w?function(a){n(a);return{__proto__:a}}:function(a){function c(){}n(a);if(null===a)throw new SyntaxError("Native Object.create is required to create objects with null prototype");c.prototype=a;return new c}),B=f.getPrototypeOf||([].__proto__===Array.prototype?function(a){a=a.__proto__;
|
||||
return l(a)?a:null}:u);var t=function(a,c){if(void 0===(this&&this instanceof t?this.constructor:void 0))throw new TypeError("Constructor Proxy requires 'new'");return v(a,c)};t.revocable=function(a,c){return v(a,c,!0)};return t};var z="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)||"undefined"!==typeof navigator&&"ReactNative"===navigator.product?global:self;z.Proxy||(z.Proxy=m(),z.Proxy.revocable=z.Proxy.revocable);})();
|
||||
(function(){function n(){function w(){return null}function m(a){return a?"object"===typeof a||"function"===typeof a:!1}function p(a){if(null!==a&&!m(a))throw new TypeError("Object prototype may only be an Object or null: "+a);}function x(a,c,B){function k(){}if(!m(a)||!m(c))throw new TypeError("Cannot create proxy with a non-object as target or handler");var g=c;c={get:null,set:null,apply:null,construct:null};for(var h in g){if(!(h in c))throw new TypeError("Proxy polyfill does not support trap '"+h+"'");c[h]=
|
||||
g[h]}"function"===typeof g&&(c.apply=g.apply.bind(g));g=C(a);var q=!1,r=!1;if("function"===typeof a){var f=function(){var b=this&&this.constructor===f,d=Array.prototype.slice.call(arguments);k(b?"construct":"apply");return b&&c.construct?c.construct.call(this,a,d):!b&&c.apply?c.apply(a,this,d):b?(d.unshift(a),new (a.bind.apply(a,d))):a.apply(this,d)};q=!0}else a instanceof Array?(f=[],r=!0):f=y||null!==g?D(g):{};var z=c.get?function(b){k("get");return c.get(this,b,f)}:function(b){k("get");return this[b]},
|
||||
E=c.set?function(b,d){k("set");c.set(this,b,d,f)}:function(b,d){k("set");this[b]=d};h=e.getOwnPropertyNames(a).map(function(b){return{name:b,source:a}});for(var l=g;l&&l!==e.prototype;)h=h.concat(e.getOwnPropertyNames(l).map(function(b){return{name:b,source:l}})),l=e.getPrototypeOf(l);var t={};h.forEach(function(b){var d=b.name;(q||r)&&d in f||t[d]||(b=e.getOwnPropertyDescriptor(b.source,d),e.defineProperty(f,d,{enumerable:!!b.enumerable,get:z.bind(a,d),set:E.bind(a,d)}),t[d]=!0)});h=!0;if(q||r){var F=
|
||||
e.setPrototypeOf||([].__proto__===Array.prototype?function(b,d){p(d);b.__proto__=d;return b}:w);g&&F(f,g)||(h=!1)}if(c.get||!h)for(var u in a)t[u]||e.defineProperty(f,u,{get:z.bind(a,u)});e.seal(a);e.seal(f);return B?{proxy:f,revoke:function(){a=null;k=function(b){throw new TypeError("Cannot perform '"+b+"' on a proxy that has been revoked");}}}:f}var e=Object,y=!!e.create||!({__proto__:null}instanceof e),D=e.create||(y?function(a){p(a);return{__proto__:a}}:function(a){function c(){}p(a);if(null===
|
||||
a)throw new SyntaxError("Native Object.create is required to create objects with null prototype");c.prototype=a;return new c}),C=e.getPrototypeOf||([].__proto__===Array.prototype?function(a){a=a.__proto__;return m(a)?a:null}:w);var v=function(a,c){if(void 0===(this&&this instanceof v?this.constructor:void 0))throw new TypeError("Constructor Proxy requires 'new'");return x(a,c)};v.revocable=function(a,c){return x(a,c,!0)};return v};var A="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)||"undefined"!==typeof navigator&&"ReactNative"===navigator.product?global:self;A.Proxy||(A.Proxy=n(),A.Proxy.revocable=A.Proxy.revocable);})();
|
||||
|
|
19
src/proxy.js
19
src/proxy.js
|
@ -170,14 +170,23 @@ module.exports = function proxyPolyfill() {
|
|||
this[prop] = value;
|
||||
};
|
||||
|
||||
// Clone direct properties (i.e., not part of a prototype).
|
||||
const propertyNames = $Object.getOwnPropertyNames(target);
|
||||
// Walk the prototype chain for all property definitions
|
||||
let propertyInfo = $Object.getOwnPropertyNames(target).map(p=>({name: p, source: target}));
|
||||
let currentProto = proto;
|
||||
while (currentProto && currentProto !== $Object.prototype){
|
||||
propertyInfo = propertyInfo.concat($Object.getOwnPropertyNames(currentProto)
|
||||
.map(p=>({name: p, source: currentProto}))
|
||||
);
|
||||
currentProto = $Object.getPrototypeOf(currentProto);
|
||||
}
|
||||
const propertyMap = {};
|
||||
propertyNames.forEach(function(prop) {
|
||||
if ((isMethod || isArray) && prop in proxy) {
|
||||
propertyInfo.forEach(function(item) {
|
||||
const prop = item.name;
|
||||
const src = item.source;
|
||||
if ((isMethod || isArray) && prop in proxy || propertyMap[prop]) {
|
||||
return; // ignore properties already here, e.g. 'bind', 'prototype' etc
|
||||
}
|
||||
const real = $Object.getOwnPropertyDescriptor(target, prop);
|
||||
const real = $Object.getOwnPropertyDescriptor(src, prop);
|
||||
const desc = {
|
||||
enumerable: Boolean(real.enumerable),
|
||||
get: getter.bind(target, prop),
|
||||
|
|
51
suite.js
51
suite.js
|
@ -270,6 +270,57 @@ module.exports = () => function(scope) {
|
|||
assert.sameMembers(called, ['foo'], 'should be called with "foo"');
|
||||
});
|
||||
|
||||
test('proxy class with class props', function() {
|
||||
class Foo {
|
||||
_foo = 'bar';
|
||||
get foo() { return this._foo };
|
||||
set foo(v) { this._foo = v };
|
||||
}
|
||||
|
||||
var called = [];
|
||||
|
||||
var inst = new Foo();
|
||||
var p = new impl(inst, {
|
||||
set(target, property, value) {
|
||||
target[property] = value;
|
||||
called.push(property);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
assert('foo' in inst, 'inst should have prop');
|
||||
assert('foo' in p, 'proxy should have prop');
|
||||
p.foo = "que";
|
||||
assert.equal(inst.foo, "que");
|
||||
assert.sameMembers(called, ['foo'], 'should be called with "foo"');
|
||||
});
|
||||
|
||||
test('proxy class with super props', function() {
|
||||
|
||||
class SuperClass {
|
||||
_foo = 'bar';
|
||||
get foo() { return this._foo };
|
||||
set foo(v) { this._foo = v };
|
||||
}
|
||||
class Foo extends SuperClass {
|
||||
}
|
||||
|
||||
var called = [];
|
||||
|
||||
var inst = new Foo();
|
||||
var p = new impl(inst, {
|
||||
set(target, property, value) {
|
||||
target[property] = value;
|
||||
called.push(property);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
assert('foo' in inst, 'inst should have prop');
|
||||
assert('foo' in p, 'proxy should have prop');
|
||||
p.foo = "que";
|
||||
assert.equal(inst.foo, "que");
|
||||
assert.sameMembers(called, ['foo'], 'should be called with "foo"');
|
||||
});
|
||||
|
||||
test('trap instance methods', function() {
|
||||
var cls = function() {
|
||||
this.y = 1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче