From 079c15c736b11c2e486315caa455ed448292d310 Mon Sep 17 00:00:00 2001 From: Utkarsh Maheshwari Date: Fri, 23 Feb 2024 12:55:11 +0530 Subject: [PATCH 1/4] Allow blocking globals in specific executions --- lib/index.js | 19 +++++++++++++------ test/unit/scope-exec.test.js | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/lib/index.js b/lib/index.js index 9b82857..a832dc9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -162,17 +162,24 @@ class Uniscope { * Executes a string within a protected Uniscope of controlled set of globals. * * @param {String} code A string representing a JavaScript expression, statement, or sequence of statements - * @param {Boolean} [async=false] When set to true, callback will be called when `__exitscope` is triggered + * @param {Object} [options] An object of options for the exec + * @param {Boolean} [options.async=false] When set to true, callback will be called when `__exitscope` is triggered * @param {Function} callback Callback function to be called at the end of execution */ - exec (code, async, callback) { + exec (code, options, callback) { // allow polymorphic parameter to enable async functions // and validate the primary code parameter - if (async && !callback) { - callback = async; - async = false; + if (options && !callback) { + callback = options; + options = {}; } + if (typeof options === 'boolean') { + options = { async: options }; + } + + const async = Boolean(options && options.async); + if (!util.isFunction(callback)) { throw new Error(ERROR_CALLBACK_MISSING); } if (!util.isString(code)) { return callback(new TypeError(ERROR_CODE_MUST_BE_STRING)); } @@ -233,7 +240,7 @@ class Uniscope { }); // based on Uniscope configuration, the globals that we block are specifically set to undefined - util.forEach(blocked, (key) => { + util.forEach(blocked.concat(options.blocked || []), (key) => { let position = globals.indexOf(key); (position === -1) && (position = globals.length); diff --git a/test/unit/scope-exec.test.js b/test/unit/scope-exec.test.js index c063874..691169f 100644 --- a/test/unit/scope-exec.test.js +++ b/test/unit/scope-exec.test.js @@ -100,4 +100,37 @@ describe('scope module exec', function () { expect(d).to.equal(4); `, done); }); + + it('should allow blocking globals in specific executions', function (done) { + scope.set('myGlobal', 'my_global'); + + scope.set('blockedExecution', function () { + scope.exec(` + expect(myGlobal).to.equal(undefined); + unblockedExecution(); // call execution from inside the blocked scope + try { + Function('return myGlobal')(); + throw new Error('myGlobal is not blocked'); + } catch (e) { + expect(e).to.be.an('error'); + expect(e.message).to.equal('myGlobal is not defined'); + } + `, { blocked: ['myGlobal'] }, function (err) { + expect(err, 'error in blockedExecution').to.be.undefined; + }); + }); + + scope.set('unblockedExecution', function () { + scope.exec(` + expect(myGlobal).to.equal('my_global'); + `, function (err) { + expect(err, 'error in unblockedExecution').to.be.undefined; + }); + }); + + scope.exec(` + blockedExecution(); + unblockedExecution(); + `, done); + }); }); From c9b27d6cdd972d2250844d7a1085e61b3f79b46e Mon Sep 17 00:00:00 2001 From: Utkarsh Maheshwari Date: Mon, 26 Feb 2024 17:15:21 +0530 Subject: [PATCH 2/4] Rename `blocked` option to `block` --- lib/index.js | 3 ++- test/unit/scope-exec.test.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index a832dc9..9776ddc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -164,6 +164,7 @@ class Uniscope { * @param {String} code A string representing a JavaScript expression, statement, or sequence of statements * @param {Object} [options] An object of options for the exec * @param {Boolean} [options.async=false] When set to true, callback will be called when `__exitscope` is triggered + * @param {String[]} [options.block] Specify a set of global variables that will not be allowed to trickle in * @param {Function} callback Callback function to be called at the end of execution */ exec (code, options, callback) { @@ -240,7 +241,7 @@ class Uniscope { }); // based on Uniscope configuration, the globals that we block are specifically set to undefined - util.forEach(blocked.concat(options.blocked || []), (key) => { + util.forEach(blocked.concat(options.block || []), (key) => { let position = globals.indexOf(key); (position === -1) && (position = globals.length); diff --git a/test/unit/scope-exec.test.js b/test/unit/scope-exec.test.js index 691169f..43b5dd9 100644 --- a/test/unit/scope-exec.test.js +++ b/test/unit/scope-exec.test.js @@ -115,7 +115,7 @@ describe('scope module exec', function () { expect(e).to.be.an('error'); expect(e.message).to.equal('myGlobal is not defined'); } - `, { blocked: ['myGlobal'] }, function (err) { + `, { block: ['myGlobal'] }, function (err) { expect(err, 'error in blockedExecution').to.be.undefined; }); }); From 8bf95674dd622ca4a03a3b7dd4346c4b83a1591a Mon Sep 17 00:00:00 2001 From: Utkarsh Maheshwari Date: Wed, 13 Mar 2024 13:43:16 +0530 Subject: [PATCH 3/4] Update CHANGELOG --- CHANGELOG.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index 60bdbf5..6817b09 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -1,3 +1,7 @@ +unreleased: + new features: + - GH-640 Added option to allow blocking globals in specific executions + 2.1.0: date: 2024-02-28 new features: From d60ea9fdb71d33937ba1ee94166649a098dfb7aa Mon Sep 17 00:00:00 2001 From: Utkarsh Maheshwari Date: Wed, 13 Mar 2024 13:44:59 +0530 Subject: [PATCH 4/4] Update README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7dfead0..f9bd68c 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ An asynchronous script will require an explicit call of a global function `__exi ```javascript myscope.set('setTimeout', global.setTimeout); // inject setTimeout -// note the 2nd parameter is set to `true` for async -myscope.exec('setTimeout(function () { __exitscope(null); }, 1000)', true, function (err) { +// note the 2nd parameter is set to `{ async: true }` +myscope.exec('setTimeout(function () { __exitscope(null); }, 1000)', { async: true }, function (err) { err ? console.error(err.stack || err) : console.log('execution complete'); }); ```