Create a helper function to run a function in an isolated area

This code works:

it.cb(h => { console.log(h); h.ctn(); }); it.cb(new Function( 'h', [ 'console.log(h)', 'h.ctn()' ] .join(';') )); 

these two tests are basically identical. But building a string with such an array is cumbersome, and you cannot get static analysis. So what I was going to do was something like this:

  it.cb(isolated(h => { console.log(h); h.ctn(); })); 

where isolated is an auxiliary function that looks something like this:

 const isolated = function(fn){ const str = fn.toString(); const paramNames = getParamNames(str); return new Function(...paramNames.concat(str)); }; 

The biggest problem is that Function.prototype.toString() provides you with the whole function. Does anyone know a good way to simply get the body of a function from a string representation of a function?

Update: Poberts asked what the purpose of this is, the goal is simple:

  const foo = 3; it.cb(isolated(h => { console.log(foo); // this will throw "ReferenceError: foo is not defined" h.ctn(); })); 
+2
source share
3 answers

I wrote an isolated() version that processes any non- bind certain user expression of the red function and throws user errors for the access scope:

 function isolated (fn) { return new Function(' with (new Proxy({}, { has () { return true; }, get (target, property) { if (typeof property !== 'string') return target[property]; throw new ReferenceError(property + ' accessed from isolated scope'); }, set (target, property) { throw new ReferenceError(property + ' accessed from isolated scope'); } })) return ${Function.prototype.toString.call(fn)} ').call(new Proxy(function () {}, new Proxy({}, { get() { throw new ReferenceError('this accessed from isolated scope'); } }))); } // test functions [ () => arguments, // fail () => this, // pass, no way to intercept this () => this.foo, // fail () => this.foo = 'bar', // fail () => this(), // fail () => new this, // fail h => h, // pass h => i, // fail (a, b) => b > a ? b : a, // pass ].forEach(fn => { const isolate = isolated(fn); console.log(isolate.toString()); try { isolate(); console.log('passed'); } catch (error) { console.log('${error.name}: ${error.message}'); } }) 

This implementation is somewhat simpler and, therefore, much less error prone than trying to analyze the parameters and body of a user-defined function.

The with statement is a relatively simplified way to intercept any links within the scope inside a forcedly isolated function and throw a ReferenceError . This is done by inserting an intermediate Proxy server into the scope with a get hook that intercepts the name of the available scope variable.

Proxy that is passed as the context of the function was the only part that was a bit difficult to implement, as well as incomplete. This was necessary because the Proxy provided as the scope for the with statement does not intercept access to the this , so the context must also be explicitly wrapped to intercept and use any indirect use of this inside an isolated arrow function.

+2
source

I would just use indexOf('{') and lastIndexOf('}') .

 const yourFunction = h => { console.log(h); h.ctn(); }; const fnText = yourFunction.toString(); const body = fnText.substring(fnText.indexOf('{') + 1, fnText.lastIndexOf('}')); console.log(body); 

Knowing that this will not cover the functions of an arrow without a body:

 const fn = k => k + 1 
+1
source

Well, it works, it was not too difficult. Suppose that the first and last parsers are the contour of the function body.

 const isolated = function(fn){ const str = fn.toString(); const first = str.indexOf('{') + 1; const last = str.lastIndexOf('}'); const body = str.substr(first, last-first); const paramNames = ['h']; return new Function(...paramNames.concat(body)); }; 

above we assume that the only argument is called "h", but you need to find a function parser. I have used require('function-arguments') in the past.

0
source

Source: https://habr.com/ru/post/1270110/


All Articles