Converting JSON string to Angular function? - javascript

I have an angular service fetching some JSON data, and in this data I have a function as a string (building it server side and passing it to angular), something like:
{
"fn": "function( data ) { data.rendered = data.value; }"
}
Is it possible to parse this and use it as an expression with angular? I.e.
settings.myCustomFunction = serviceData.fn;
I've attempted to do this with different combinations of eval, $eval, $parse, but I haven't had any luck with any of them. They all either throw errors about "Unexpected *" or don't throw errors, but also don't seem to do anything.

You could wrap the string in parentheses to avoid the syntax error.
eval("(" + fnString + ")")
This makes it a syntactically valid JavaScript statement which is composed of a single function expression that you can pass around freely.
An anonymous function by itself, without any parentheses or LHS operators (like the commonly used assignment operator =) acting upon it, is not a syntactically valid JavaScript statement. That's why you'll see IIFEs (immediately invoked function expressions) wrapped up in parentheses in JS:
(function() {
// ...
})()

If you really want to get eval to work, then you can do this:
var settings = {};
eval("settings.myCustomFunction = " + serviceData.fn);
Using eval in this way of course opens your app up to possible malicious script injections.

You could do user new Function():
settings.myCustomFunction = new Function('argument',functionbody);
To execute:
settings.myCustomFunction();//

You might want to check out eval.call. This allows you to not care what the arguments are and use any arguments from strings. Of course to call it you must use the same arguments, BUT, you could string-drive that too, by concatting the args together when you eval.call it.
{
"fn": "function( data ) { return data + 1; }"
}
Example:
var serviceData = {
fn: '(function (data) {return data + 1;})'
};
var data = 44;
var result = window.eval.call(window, serviceData.fn)(data);
console.log(result); // 45

Related

How to parse functions bodies from a string using javascript?

I'm looking for a way to get a function declaration body by name from a string of js code. I'm in Nodejs environment.
Let's say I have some spaghetti.js file. I can read it into a string
const allJs = fs.readFileSync('spaghetti.js');
Now I need a function that receives that string and function name and returns a string with everything between { }.
Something like this
allJs = 'let a=1; const b=[2, 3]; function cook(items){return items}; cook(b)';
parseFunction(allJs, 'cook');//'return items'
The complexity of input js is not limited.
I tried to find an npm module for that, but no luck.
You should have a look at an AST parser for Javascript:
http://esprima.org/
https://github.com/ternjs/acorn
That should be more safe than using RegExp or something.
A String can be evaluated locally with the native eval() method. But remember, eval is a form of evil!
If the parseFunction() above is relying on something like this then the global Function constructor is being used and the 'new' function is bound to the return value of that operation (and thus that return value itself needs to be called).
A simple way to achieve this might be to do something like this...
var funcString = 'var a = 1, b = 3;';
funcString += 'function summit(){return a + b;}';
funcString += 'return summit();';
function makeNewFunc(str) {
return new Function(str);
}
var newFunc = makeNewFunc( funcString );
console.log('newFunc:',newFunc);
//-> newFunc: function anonymous()
console.log('newFunc():',newFunc());
//-> newFunc(): 4
This demonstrates how functions can be created and invoked from String snippets. (EDIT: Turning something like that into a Node module is a simple matter);
Hope that helped. :)

Calling a function bypassing eval()

I am working with a Javascript code that uses eval function.
eval(myString)
The value of myString = myFunc(arg), I want to call myFunc directly without using eval.
I dont have any control over the function to call as I am getting that function as a String (here myString).
The arguments to that function is also part of the same string.
So, is there any way through which I can call the intended function without using eval?
I'm a bit skeptical of allowing users to provide function names at all, but... Assume you have the function name in a variable and the value of arg in a variable. Boom:
var myString = window[fn](arg);
arg is already presumably in an argument, so that's simple enough. The next part is exatracting the function name. Just a bit of regex:
var fn = /^([a-z0-9_]+)\(arg\)$/i.exec(str)[1];
if (fn && typeof window[fn] === 'function') {
window[fn](arg);
}
This does of course assume that the function is always in the global scope, but if it's not, you should be able to adjust accordingly for that. Also, my regex is just the first thing I came up with. It probably doesn't cover all possible function names.
If you wanted to limit the string to just a certain set of functions (and you almost certainly should), that becomes quite easy as well once you have the function name:
var allowedFunctions = {fn1: fn1, fn2: fn2, someOtherFunction: function() {} },
fn = /^([a-z0-9_]+)\(arg\)$/i.exec(str)[1];
if (fn && allowedFunctions[fn]) {
allowedFunctions[fn](arg);
} else {
// Hah, nice try.
}
(If arg isn't actually a variable name but is some kind of literal or perhaps an arbitrary expression, this gets a little more complicated and a lot less safe.)
JavaScript does not provide any way of calling a function represented as a string, other than using eval. There's nothing wrong about using it, though. Given that you have no other option.
Possibly you may try using Function:
var sure = function(s) {
return confirm(s);
};
var str = 'sure("Are you sure?")';
var rtn = new Function('return ' + str)();
alert(rtn);

Difference between JSON.parse() and eval()

May need a Javascript language lawyer for this one:
var s1 = "{\"x\":\"y:z\"}"
var o = JSON.parse(s1)
var s2 = JSON.stringify(o)
$('span#s').text(s1);
$('span#s2').text(s2);
if (s1 === s2) {
$('span#areEqual').text('s1 === s2')
} else {
$('span#areEqual').text('s1 !== s2')
}
JSON.parse(s2) // okay
$('span#jsonParse').text("JSON.parse(s2) okay")
eval(s2) // bad mojo!
$('span#eval').text("eval(s2) okay")
eval("("+s2+")") // bad mojo, too!
$('span#eval2').text("eval((s2)) okay")
eval fails on s1, s2, and "("+s2+")".
jsFiddle here.
Your problem is that you mixing two unrelated things.
eval() is built-in javascript function, which main purpose is to interpret string of javascript code (thus make potentional security hole)
JSON.parse() function is for parse JSON string. Although very simmilar, do not make mistake, JSON is not Javascript and there are tiny differences. You should not use eval() for parsing JSON
What are the differences between JSON and JavaScript object?
$eval is automatically evaluated against a given scope.
For example:
$scope.a = 2;
var result = $scope.$eval('1+1+a');
// result is 4
$parse does not require scope. It takes an expression as a parameter and returns a function. The function can be invoked with an object that can resolve the locals:
For example:
var fn = $parse('1+1+a');
var result = fn({ a: 2 });
// result is 4
When you use eval for parsing JSON you need to wrap your expression with parentheses
eval('(' + s2 + ')');
jsfiddle
Check out what the specification says about JSON and eval
http://www.json.org/js.html
Notice this part specifically
The eval function is very fast. However, it can compile and execute
any JavaScript program, so there can be security issues. The use of
eval is indicated when the source is trusted and competent. It is much
safer to use a JSON parser. In web applications over XMLHttpRequest,
communication is permitted only to the same origin that provide that
page, so it is trusted. But it might not be competent. If the server
is not rigorous in its JSON encoding, or if it does not scrupulously
validate all of its inputs, then it could deliver invalid JSON text
that could be carrying dangerous script. The eval function would
execute the script, unleashing its malice.
JSON is just a javascript object, and nothing more. Valid javascript could include functions, execution blocks, etc. If you just eval() a string, it could have code it in. JSON will parse if it's just JSON, but you can't know for sure by just stuffing it into eval. For example
var s = "(function(){ /* do badStuff */ return {s: 123, t: 456}; })()";
var result = eval(s);
Would give you a var result with the contents {s: 123, t: 456} but would also execute any code hidden in your function. If you were taking this input from elsewhere, code could be executing and not actually break anything on your end. Now the same example with JSON.parse
var result = JSON.parse(s);
It throws an error with the message:
Uncaught SyntaxError: Unexpected token (
So the parse saves you from remote code execution here, even if someone tried to sneak it in.
eval wasn't an expression - i've updated it to evaluate eval(s2 === s1);
Otherwise it will try & execute what's within the eval & stop execution.
eval() attempts to evaluate a block of JavaScript code. If you had created a script file that started with the same text, you would have gotten the same error. In that context, I believe the braces signify a compound statement, as in an if-statement or for-statement body, but at the beginning of the compound statement is a string followed by a colon, which is not valid syntax.
If you wanted a string that would evaluate to an object, you'd have to enclose the object expression in parentheses to make it explicit that it's an expression. But as apocalypz says, you should not attempt to eval JSON. It's wrong on so many levels.
if you really want to use eval instead of JSON.parse() for parsing JSON then you should write something like
var o2; // declare o2 out of eval in case of "use strict"
eval("o2 = "+s1); // parse s1 and the assignment to the local o2
console.log(o2); // enjoy the local variable :)
...

Javascript change string to type function?

I have a list of functions stored as strings such as this one:
var act= "function () { alert() }";
I need to change the type of act from 'string' to 'function' so I can .call() it. I should end up with this:
act = function () { alert() };
How can this be done?
This is one of the few cases where using eval is not only valid but correct:
var act = eval(function_string);
However, I should note that having a bunch of functions in strings is a sign of bad design. Still, if you must then eval is the way to do it.
Try this:
var act = 'alert(5);';
act = new Function( act );
I guess you have to do it with eval. But many people consider it as evil (Be sure that you get the string from a safe source.)
var act= "function () { alert() }";
eval ('act = '+ act)
You can use eval, although it is considered to be particularly unsafe if the string source is unknown. You can't really assign what you have there to any variable. eval argument has to be an expression or a statement. You can do something like this.
eval("var act = function () { alert('hey') }");
act();​

JavaScript eval() "syntax error" on parsing a function string

I have a bit of JavaScript code that is specified in a configuration file on the server-side. Since I can't specify a JavaScript function in the configuration language (Lua), I have it as a string. The server returns the string in some JSON and I have the client interpret it using a clean-up function:
parse_fields = function(fields) {
for (var i = 0; i < fields.length; ++i) {
if (fields[i].sortType) {
sort_string = fields[i].sortType;
fields[i].sortType = eval(sort_string);
}
return fields;
}
};
So basically it just evaluates sortType if it exists. The problem is that Firebug is reporting a "Syntax error" on the eval() line. When I run the same steps on the Firebug console, it works with no problems and I can execute the function as I expect. I've tried some different variations: window.eval instead of plain eval, storing the sortType as I've done above, and trying small variations to the string.
A sample value of fields[i].sortType is "function(value) { return Math.abs(value); }". Here's the testing I did in Firebug console:
>>> sort_string
"function(value) { return Math.abs(value); }"
>>> eval(sort_string)
function()
>>> eval(sort_string)(-1)
1
and the error itself in Firebug:
syntax error
[Break on this error] function(value) { return Math.abs(value); }
The last bit that may be relevant is that this is all wrapped in an Ext JS onReady() function, with an Ext.ns namespace change at the top. But I assumed the window.eval would call the global eval, regardless of any possible eval in more specific namespaces.
Any ideas are appreciated.
To do what you want, wrap your string in parentheses:
a = "function(value) { return Math.abs(value);}";
b = eval("("+a+")");
b(-1);
The parentheses are required because they force the thing inside them to be evaluated in an expression context, where it must be a function-expression.
Without the parentheses, it could instead be a function declaration, and it seems as if it is sometimes being parsed that way - this could be the source of the odd/inconsistent behaviour you're describing.
Compare this function declaration:
function foo(arg) {}
with this function-expression:
var funcExpr = function foo(arg) {};
It also has to be a function-expression if it doesn't have a name. Function declarations require names.
So this is not a valid declaration, because it's missing its name:
function (arg) {}
but this is a valid, anonymous function-expression:
var funcExpr = function(arg) {};

Categories