From 4d80f51360396c2fb2fc64c1656ae6aa867255f1 Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Sat, 18 Jan 2014 18:58:38 +0100 Subject: [PATCH 1/3] Added Context to emulate node behaviour. --- index.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 3446ee2..b6cfcbd 100644 --- a/index.js +++ b/index.js @@ -16,13 +16,18 @@ var forEach = function (xs, fn) { } }; +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 = {}; @@ -63,11 +68,8 @@ 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) { + return this.runInContext(Script.createContext(context)); }; forEach(Object_keys(Script.prototype), function (name) { @@ -82,9 +84,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]; From affa956374312706278d8c84f011f7164e607259 Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Sat, 18 Jan 2014 19:25:01 +0100 Subject: [PATCH 2/3] runInNewContext should modify passed object. --- index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index b6cfcbd..2940ce4 100644 --- a/index.js +++ b/index.js @@ -69,7 +69,14 @@ Script.prototype.runInThisContext = function () { }; Script.prototype.runInNewContext = function (context) { - return this.runInContext(Script.createContext(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) { From 7f9e050e81c26c6cf7d2baab2a0d2d9b39597c92 Mon Sep 17 00:00:00 2001 From: Alan Plum Date: Mon, 20 Jan 2014 19:27:54 +0100 Subject: [PATCH 3/3] Adding non-enumerable properties to context like node does. --- index.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 2940ce4..3aa6790 100644 --- a/index.js +++ b/index.js @@ -16,6 +16,30 @@ 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 = {}; @@ -40,7 +64,12 @@ Script.prototype.runInContext = 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'); @@ -58,6 +87,12 @@ Script.prototype.runInContext = function (context) { context[key] = win[key]; } }); + + forEach(globals, function (key) { + if (!(key in context)) { + defineProp(context, key, win[key]); + } + }); document.body.removeChild(iframe);