NeilFraser / JS-Interpreter

A sandboxed JavaScript interpreter in JavaScript.
Apache License 2.0
2.01k stars 353 forks source link

How to get the function in the return value #249

Closed 805808786 closed 8 months ago

805808786 commented 1 year ago

I am using JS-Interpreter to parse the code blocks entered by the user in the editor. I hope to get the functions entered by the user in some cases, so that these code blocks can participate in some business logic, but in fact I can't get these data.

const initChart = (editorContent) => {
    const option = JSSandbox(editorContent, { echarts });
    // option.series[0].textStyle.normal.color is {}
    // But I hope it is a function
    console.log(option);
    if (Object.prototype.toString.call(option) === '[object Object]') {
      const chart = echarts.init(ref.current);
      chart.clear();
      chart.setOption(option);
    }
  };

my case

NeilFraser commented 8 months ago

My understanding is that you are expecting a user to enter some code (hopefully a function) into your editor, and you want to know the function name that has been defined. For example, the user enters this code:

function foo() {
  alert('hello')
}

And you want to know that the function is called foo.

The best way I can think of is to compare the global variables before and after the code is injected.

// Create an empty interpreter with no code (and an initFunc for any custom API functions).
var myInterpreter = new Interpreter('', initFunc);
// Record the global names in an empty JavaScript environment.
var oldGlobals = Object.getOwnPropertyNames(myInterpreter.getGlobalScope().object.properties);
// Load the user's code.
myInterpreter.appendCode(code);
// Record the global names after the user's code has been added.
var newGlobals = Object.getOwnPropertyNames(myInterpreter.getGlobalScope().object.properties);
// Compute the difference to determine what's new.
var userGlobals = newGlobals.filter(n => !oldGlobals.includes(n));

This produces an array of all globals which the user's code created. Hopefully that will be the function they defined. But it could also be a global variable. You can use this code to find out if a particular value is a function or not:

myInterpreter.getValueFromScope('foo').class === 'Function'
cpcallen commented 8 months ago

I think a better approach would be to parse the user-provided code using Acorn and extract the function names from the generated AST. This avoids a whole host of potential pitfalls and additionally obviates the need to use JS Interpreter for this task.