diff --git a/index.js b/index.js index 3446ee2..3aa6790 100644 --- a/index.js +++ b/index.js @@ -16,13 +16,42 @@ var forEach = function (xs, fn) { } }; +var defineProp = (function() { + try { + Object.defineProperty({}, '_', {}); + return function(obj, name, value) { + Object.defineProperty(obj, name, { + writable: true, + enumerable: false, + configurable: true, + value: value + }) + }; + } catch(e) { + return function(obj, name, value) { + obj[name] = value; + }; + } +}()); + +var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function', +'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', +'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError', +'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', +'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape']; + +function Context() {} +Context.prototype = {}; + var Script = exports.Script = function NodeScript (code) { if (!(this instanceof Script)) return new Script(code); this.code = code; }; -Script.prototype.runInNewContext = function (context) { - if (!context) context = {}; +Script.prototype.runInContext = function (context) { + if (!(context instanceof Context)) { + throw new TypeError("needs a 'context' argument."); + } var iframe = document.createElement('iframe'); if (!iframe.style) iframe.style = {}; @@ -35,7 +64,12 @@ Script.prototype.runInNewContext = function (context) { forEach(Object_keys(context), function (key) { win[key] = context[key]; }); - + forEach(globals, function (key) { + if (context[key]) { + win[key] = context[key]; + } + }); + if (!win.eval && win.execScript) { // win.eval() magically appears when this is called in IE: win.execScript('null'); @@ -53,6 +87,12 @@ Script.prototype.runInNewContext = function (context) { context[key] = win[key]; } }); + + forEach(globals, function (key) { + if (!(key in context)) { + defineProp(context, key, win[key]); + } + }); document.body.removeChild(iframe); @@ -63,11 +103,15 @@ Script.prototype.runInThisContext = function () { return eval(this.code); // maybe... }; -Script.prototype.runInContext = function (context) { - // seems to be just runInNewContext on magical context objects which are - // otherwise indistinguishable from objects except plain old objects - // for the parameter segfaults node - return this.runInNewContext(context); +Script.prototype.runInNewContext = function (context) { + var ctx = Script.createContext(context); + var res = this.runInContext(ctx); + + forEach(Object_keys(ctx), function (key) { + context[key] = ctx[key]; + }); + + return res; }; forEach(Object_keys(Script.prototype), function (name) { @@ -82,9 +126,7 @@ exports.createScript = function (code) { }; exports.createContext = Script.createContext = function (context) { - // not really sure what this one does - // seems to just make a shallow copy - var copy = {}; + var copy = new Context(); if(typeof context === 'object') { forEach(Object_keys(context), function (key) { copy[key] = context[key];