I used Esprima.Net (https://github.com/Diullei/Esprima.NET) to get AST (Abstract Syntax Key) from a JavaScript code. It returns a List<Dynamic> consisting many child and sub-child nodes. I wonder how best to traverse all these nodes in C# for analysis. Basically I want to get the function name, variable name & function that it is under.
For example, in the following JavaScript code:
var y = 45;
function fTest(d)
{
var key: Argument.Callee;
var cars = 'Hello';
for (i = 0; i < cars.length; i++)
{
text += cars[i];
}
}
I wish to get the following result at the end:
variable: 45
function:parameter:'d'
function:variable:argument.callee
function:variable:'Hello'
funtion:loop:variable:object
I'm having a difficulty to traverse the List<Dynamic> given by Esprima.Net. Any ideas to process or traverse this list in a Tree or any structure so that I can access them? Thanks.
I ended up not using the Esprima.NET but Esprima JS (http://esprima.org/). I added Esprima JS in webpage and create an external javascript file that called Esprima parser to create AST. Once I had the AST, I used estraverse (https://github.com/estools/estraverse) to traverse the AST to get results.
Hope this helps others.
You can use Jint which is a JavaScript interpreter in .NET, and has an internal port of Esprima (ES5). It returns the same AST as Esprima.
Or you can use this other Esprima.NET that is based on ES6 and distributed separately from Jint.
Related
In Javascript or PHP this is fairly easy but doesn't seem to work for extendscript.
I have a search function that stores it's results in a var. I want to see what is in the var after the function runs. So usually I use a alert() but InDesign comes up with a box containing [object Word].
Here is what I do:
var myFound = myDoc.findGrep();
alert(myFound);
InDesign throws me this box:
If I do the following:
alert(myFound.length);
Any ideas how to "reveal" my content?
If someone wants to know how to fix it:
Create an array around the for loop and gather the information in it.
After that alert the array like this:
var myFound = myDoc.findGrep();
var result = new Array();
for(i=0; i<myFound.length; i++)
{
result[result.length] = myFound[i].contents;
}
alert(result);
The result of a grep search is an array. You need loop through it and access the word.contents
In this case, I entirely use $.writeln() instead of alert().
or use
milligramme/scriptui_scrollable_alert
I have found this site (http://jongware.mit.edu/idcs6js) immensely useful in understanding ExtendScripts InDesign objects. In particular, your Words object is here, which is an array of Word instances.
In addition, I've used Use Visual Studio Code with the ExtendScript Debugger which helpful for watching variables.
I am using mustache to build out a single string, replacing several variables within it. I would love to use a TemplateString instead, but I need to resolve my string at runtime, and not at code-compile time since I am reading the template string from an external source.
To be clear:
// mustachy example
// template is "foo{{who}}" and myData.whmustao = "manchu"
let myResult = mustache.render(getMyTemplate(),myData);
console.log(myResult); // "foomanchu"
This is pretty lightweight, and I would love to use a TemplateString, but as the example below aludes to - I can't imagine a way to externally provide the string in the first place...
// ES6xy example
let myResult = `foo${myData.who}`; // can't get this at runtime
console.log(myResult); // "foomanchu"
But, I can't imagine a straight-forward, clean, non-sneaky way of achieving this. Can you?
I'm assuming that you're loading data on the client and want to generate a string based on the data returned. You could have a function available that returns the generated string for you
function generateString(val1, val2) {
return `foo${val1} bar${val2};
}
can you call that function on the client as a result of an api call that gets val1 and val2?
this strategy would also work on the server if you delay your response until you have all the data you need
put the template-string into a function, and pass myData
let renderMyTemplate = data => `foo${data.who}`;
//or
let renderMyTemplate = ({who}) => `foo${who}`;
let myResult = renderMyTemplate(myData);
console.log(myResult);
Thank you for your replies and creative solutions. However, I thought that there was no solution because TemplateStrings are an in-code feature, whereas other template solutions (like mustache) are a data-driven feature.
Put in other words, ES6's Template Strings is a language feature which limits its functionality to static in-code strings. Any other imagined flexibilities must rely on dynamic execution of a code you inject into your application, which is every hacker's dream.
So the answer to my original thought, as to whether Mustache is overkill for a simple string that is not hard-coded in your source - is NO. Mustache is the acceptable solution for that scenario.
I'm using Scala.js, and have written a trait that is implemented for both JVM and JS. I'm using third-party JVM and JS libraries to implement it in the two sides, which should provide functionally equivalent results in the JVM and browser. But, I need to write a test to verify that!
If I were just testing two vanilla Scala implementations, I'd know how to do it. I'd write generators of the trait's inputs, and drive each function from those, comparing the results of each. (I can assume that either the function results are booleans, integers, longs, strings, collections of same, or could be toString()'d.)
Is anyone out there doing this kind of testing?
How would I do this where one implementation is in Javascript? Phantom? (Can I pass a generated JS file to it, rather than simple JS-as-strings?) Something else?
You can use Scala's reflective toolbox in a macro to execute your test code at compilation time (on the JVM). You can then use the result and generate code that compares the value.
So we want to write a macro, that given the following code:
FuncTest.test { (1.0).toString }
Can generate something like this:
assert("1.0" == (1.0).toString)
This actually sounds harder than in is. Let's start with a macro skeleton for FuncTest:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
object FuncTest {
def test[T](x: => T): Unit = macro FuncTestImpl.impl[T]
}
class FuncTestImpl(val c: Context) {
import c.universe._
def impl[T : WeakTypeTag](x: Tree): Tree = ???
}
Inside impl, we want to run the code in x and then generate an assertion (or whatever suits the test framework you use):
import scala.reflect.runtime.{universe => ru}
import scala.tools.reflect.ToolBox
def impl[T : WeakTypeTag](x: Tree): Tree = {
// Make a tool box (runtime compiler and evaluater)
val mirror = ru.runtimeMirror(getClass.getClassLoader)
val toolBox = mirror.mkToolBox()
// Import trees from compile time to runtime universe
val importer = ru.mkImporter(c.universe)
val tree = toolBox.untypecheck(importer.importTree(x))
// Evaluate expression and make a literal tree
val result = toolBox.eval(tree)
val resultTree = reifyLiteral(result)
// Emit assertion
q"assert($x == $resultTree)"
}
The only problem we have, is reifyLiteral. It basically is supposed to take an arbitrary value and create a literal out of it. This is hard / impossible in general. However, it is very easy for some basic values (primitives, strings, etc.):
/** Creates a literal tree out of a value (if possible) */
private def reifyLiteral(x: Any): Tree = x match {
case x: Int => q"$x"
case x: String => q"$x"
// Example for Seq
case x: Seq[_] =>
val elems = x.map(reifyLiteral)
q"Seq(..$elems)"
case _ =>
c.abort(c.enclosingPosition, s"Cannot reify $x of type ${x.getClass}")
}
That's it. You can now write:
FuncTest.test { /* your code */ }
To automatically generate tests for computational libraries.
Caveat The toolbox does not get the right classpath injected at the moment. So if you use an external library (which I assume you do), you will need to tweak that as well. Let me know if you need help there.
I currently use Jsoup to parse the DOM-tree of webpages. I have a separate application rendering the page and using JavaScript to extract the rendering position of every DOM-node. I use the JavaFX stage, webEngine, webView and executeScript functionality to execute the following JavaScript:
var all = document.getElementsByTagName("*");
var serialization = "";
var width = window.innerWidth;
var height = window.innerHeight;
for (var i = 0, max=all.length; i < max; i++) {
serialization += all.item(i).tagName+": "+all.item(i).offsetLeft+" "+all.item(i).offsetTop+" "+all.item(i).offsetWidth/width+" "+all.item(i).offsetHeight/height+"\n";
}
serialization
The problem I face now is to associate the output I get from the JavaScript with the information I collect from the Jsoup mechanics. Ie I want to add the rendering position of every node to the Jsoup data structure. Is there some unique ID for each DOM-node that I dont know about, or should I try a completely different approach?
I think you can use xPath as the unique identifier in both DOM and JSoup.
refer to this question How to calculate the XPath position of an element using Javascript? to get the xpath by javascript
follow the same idea to write a function in Java to get xpath by JSoup
Then you can compare each nodes by these 2 xpath expression. Hope this clarifies.
I am new to Rhino parser. Can i use this rhino parser in javascript code to extract the Abstract Syntax Tree of javascript code in any html file. If so ho should i start this.This is for Analyzing AST of the code for computing the ratio between keywords and words used in javascript, to identify common decryption schemes, and to calculate the occurrences of certain classes of function calls such as fromCharCode(), eval(),and some string functions that are commonly used for the decryption
and execution of drive-by-download exploits.
As far as I know, you can't access the AST from JavaScript in Rhino. I would look at the Esprima parser though. It's a complete JavaScript parser written in JavaScript and it has a simple API for doing code analysis.
Here's a simple example that calculates the keyword to identifier ratio:
var tokens = esprima.parse(script, { tokens: true }).tokens;
var identifierCount = 0;
var keywordCount = 0;
tokens.forEach(function (token) {
if (token.type === 'Keyword') {
keywordCount++;
}
else if (token.type === 'Identifier') {
identifierCount++;
}
});
var ratio = keywordCount / identifierCount;