diff --git a/README.md b/README.md index b5e9d08..70b2cc4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This is a polyfill for the `Proxy` object, part of ES6. See the [MDN docs](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy) or [Introducing ES2015 Proxies](https://developers.google.com/web/updates/2016/02/es2015-proxies) for more information on `Proxy` itself. -Unlike other polyfills, this does not require `Object.observe`, [which is deprecated](https://www.google.com/search?q=object.observe+deprecated). +Unlike other polyfills, this does not require `Object.observe`, [which is no longer supported anywhere](https://www.google.com/search?q=object.observe+deprecated). The polyfill supports just a limited number of proxy 'traps'. It also works by calling [seal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) on the object passed to `Proxy`. @@ -69,10 +69,10 @@ function observe(o, callback) { return buildProxy('', o); } -const x = {'model': {name: 'Falcon'}}; +const x = {'model': {name: 'LEAF'}}; const p = observe(x, (property, value) => console.info(property, value)); -p.model.name = 'Commodore'; -// model.name Commodore +p.model.name = 'Tesla'; +// model.name Tesla ``` ## Adding new properties @@ -94,48 +94,34 @@ For a similar reason, this polyfill can't proxy `Array` objects very well - but # Usage -## To assign Proxy to the global object +Install via your favourite package manager as `proxy-polyfill`. -Include the JavaScript at the start of your page, as an ES6 module (although browsers that support ES6 modules support `Proxy` natively) or include it as a dependency to your build steps. -The source is in ES6, but the included, minified version is ES5. +## To polyfill Proxy everywhere -## To consume Proxy as a function +You should include `proxy-polyfill` into your build system (just require it directly, it doesn't export anything), or import the `proxy.min.js` file directly. +This is the recommended approach and works on the web, in Node, or React Native. -Require from your app the file `./src/proxy.js`, which exports a proxy polyfill functionvian commonJS. +## To consume the polyfill as a function + +Requires `./src/proxy.js`, which exports a proxy polyfill _builder_ function in commonJS. ```js // commonJS require -const ProxyPolyfill = require('proxy-polyfill/src/proxy'); +const proxyPolyfill = require('proxy-polyfill/src/proxy')(); // Your environment may also support transparent rewriting of commonJS to ES6: -import ProxyPolyfill from 'proxy-polyfill/src/proxy'; +import ProxyPolyfillBuilder from 'proxy-polyfill/src/proxy'; +const proxyPolyfill = ProxyPolyfillBuilder(); // Then use... -const myProxy = new ProxyPolyfill(...); -``` - -## Installation - -Available via NPM or Bower- - -```bash -$ npm install proxy-polyfill -$ bower install proxy-polyfill +const myProxy = new proxyPolyfill(...); ``` -If this is imported as a Node module, it will polyfill the global namespace rather than returning the `Proxy` object. -If you'd like to just get the polyfill'ed version, use the require statement as above. - -## Supports +# Support The polyfill supports browsers that implement the full [ES5 spec](http://kangax.github.io/compat-table/es5/), such as IE9+ and Safari 6+. It may work in other non-browser environments too. Note that Firefox, Chrome, Safari 10+ and Edge support `Proxy` natively. +You don't need this if you're only targeting these modern browsers. -# Release - -Run -```bash -$ npm run build -``` diff --git a/build.js b/build.js index f066117..5022ef3 100644 --- a/build.js +++ b/build.js @@ -23,10 +23,9 @@ const closureCompiler = new ClosureCompiler({ language_in: 'ECMASCRIPT6_STRICT', language_out: 'ECMASCRIPT5', compilation_level: 'ADVANCED_OPTIMIZATIONS', -// dependency_mode: 'STRICT', warning_level: 'VERBOSE', process_common_js_modules: true, - output_wrapper: '(function(){%output%})()', // this prevents closure compiler from polluting the global scope + output_wrapper: '(function(){%output%})();', // don't pollute global scope }); const compilerProcess = closureCompiler.run((code, stdout, stderr) => { diff --git a/proxy.min.js b/proxy.min.js index 4bf7bd9..292e1d6 100644 --- a/proxy.min.js +++ b/proxy.min.js @@ -1,4 +1,4 @@ -(function(){function k(){function n(a){return a?"object"===typeof a||"function"===typeof a:!1}var p=null;var m=function(a,c){function g(){}if(!n(a)||!n(c))throw new TypeError("Cannot create proxy with a non-object as target or handler");p=function(){g=function(b){throw new TypeError("Cannot perform '"+b+"' on a proxy that has been revoked");}};var f=c;c={get:null,set:null,apply:null,construct:null};for(var h in f){if(!(h in c))throw new TypeError("Proxy polyfill does not support trap '"+h+"'");c[h]=f[h]}"function"=== -typeof f&&(c.apply=f.apply.bind(f));var d=this,q=!1,r=!1;"function"===typeof a?(d=function(){var b=this&&this.constructor===d,e=Array.prototype.slice.call(arguments);g(b?"construct":"apply");return b&&c.construct?c.construct.call(this,a,e):!b&&c.apply?c.apply(a,this,e):b?(e.unshift(a),new (a.bind.apply(a,e))):a.apply(this,e)},q=!0):a instanceof Array&&(d=[],r=!0);var t=c.get?function(b){g("get");return c.get(this,b,d)}:function(b){g("get");return this[b]},w=c.set?function(b,e){g("set");c.set(this, -b,e,d)}:function(b,e){g("set");this[b]=e},u={};Object.getOwnPropertyNames(a).forEach(function(b){if(!((q||r)&&b in d)){var e={enumerable:!!Object.getOwnPropertyDescriptor(a,b).enumerable,get:t.bind(a,b),set:w.bind(a,b)};Object.defineProperty(d,b,e);u[b]=!0}});f=!0;Object.setPrototypeOf?Object.setPrototypeOf(d,Object.getPrototypeOf(a)):d.__proto__?d.__proto__=a.__proto__:f=!1;if(c.get||!f)for(var l in a)u[l]||Object.defineProperty(d,l,{get:t.bind(a,l)});Object.seal(a);Object.seal(d);return d};m.revocable= -function(a,c){return{proxy:new m(a,c),revoke:p}};return m};var v="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)||"undefined"!==typeof navigator&&"ReactNative"===navigator.product?global:self;v.Proxy||(v.Proxy=k(),v.Proxy.revocable=v.Proxy.revocable);})() +(function(){function k(){function p(a){return a?"object"===typeof a||"function"===typeof a:!1}var l=null;var n=function(a,c){function g(){}if(!p(a)||!p(c))throw new TypeError("Cannot create proxy with a non-object as target or handler");l=function(){a=null;g=function(b){throw new TypeError("Cannot perform '"+b+"' on a proxy that has been revoked");}};setTimeout(function(){l=null},0);var f=c;c={get:null,set:null,apply:null,construct:null};for(var h in f){if(!(h in c))throw new TypeError("Proxy polyfill does not support trap '"+ +h+"'");c[h]=f[h]}"function"===typeof f&&(c.apply=f.apply.bind(f));var d=this,q=!1,r=!1;"function"===typeof a?(d=function(){var b=this&&this.constructor===d,e=Array.prototype.slice.call(arguments);g(b?"construct":"apply");return b&&c.construct?c.construct.call(this,a,e):!b&&c.apply?c.apply(a,this,e):b?(e.unshift(a),new (a.bind.apply(a,e))):a.apply(this,e)},q=!0):a instanceof Array&&(d=[],r=!0);var t=c.get?function(b){g("get");return c.get(this,b,d)}:function(b){g("get");return this[b]},w=c.set?function(b, +e){g("set");c.set(this,b,e,d)}:function(b,e){g("set");this[b]=e},u={};Object.getOwnPropertyNames(a).forEach(function(b){if(!((q||r)&&b in d)){var e={enumerable:!!Object.getOwnPropertyDescriptor(a,b).enumerable,get:t.bind(a,b),set:w.bind(a,b)};Object.defineProperty(d,b,e);u[b]=!0}});f=!0;Object.setPrototypeOf?Object.setPrototypeOf(d,Object.getPrototypeOf(a)):d.__proto__?d.__proto__=a.__proto__:f=!1;if(c.get||!f)for(var m in a)u[m]||Object.defineProperty(d,m,{get:t.bind(a,m)});Object.seal(a);Object.seal(d); +return d};n.revocable=function(a,c){return{proxy:new n(a,c),revoke:l}};return n};var v="undefined"!==typeof process&&"[object process]"==={}.toString.call(process)||"undefined"!==typeof navigator&&"ReactNative"===navigator.product?global:self;v.Proxy||(v.Proxy=k(),v.Proxy.revocable=v.Proxy.revocable);})(); diff --git a/src/proxy.js b/src/proxy.js index 312b412..0316395 100644 --- a/src/proxy.js +++ b/src/proxy.js @@ -41,10 +41,15 @@ module.exports = function proxyPolyfill() { // to call itself, but that seems unlikely especially when using the polyfill. let throwRevoked = function() {}; lastRevokeFn = function() { + /** @suppress {checkTypes} */ + target = null; // clear ref throwRevoked = function(trap) { throw new TypeError(`Cannot perform '${trap}' on a proxy that has been revoked`); }; }; + setTimeout(function() { + lastRevokeFn = null; + }, 0); // Fail on unsupported traps: Chrome doesn't do this, but ensure that users of the polyfill // are a bit more careful. Copy the internal parts of handler to prevent user changes.