JINT - Unable to "console.log" - c#

I am new to JINT, and trying to just do some basic tests to kind of learn the ropes. My first attempt was to just store some javascript in my database, load it, and execute it in a unit test. So that looks essentially like this....
[Fact]
public void can_use_jint_engine() {
using (var database = DocumentStore()) {
using (var session = database.OpenSession()) {
var source = session.Load<Statistic>("statistics/1");
// join the list of strings into a single script
var script = String.Join("\n", source.Scripting);
// this will create the script
// console.log("this is a test from jint.");
//
var engine = new Jint.Engine();
// attempt to execute the script
engine.Execute(script);
}
}
}
And it doesn't work, I get this error, which makes absolutely no sense to me, and I cannot find any documentation on.
Jint.Runtime.JavaScriptExceptionconsole is not defined at
Jint.Engine.Execute(Program program) at
Jint.Engine.Execute(String source) at
SampleProject.Installers.Instanced.__testing_installer.can_use_jint_engine()
in _testing_installer.cs: line 318
Can anyone assist in shedding some light on this? I'm pretty confused at this point.

With JavaScript there are three entities - we care about. The host (browser, your application etc), the engine (JINT in this case) and the script ("console.log(...)") in this case.
JavaScript defines a bunch of functions and object as part of the language, but console is not one of them. By convention, browsers define a console object that can be used in the manner you describe. However, since your app is not a browser (and JINT does not do this by itself), there's no console object defined in your namespace (globals).
What you need to do is add a console object that will be accessible in JINT. You can find how to do this in the docs, but here's a simple example of how to add a log function to the engine so it can be used from the JS code (example taken from github).
var engine = new Engine()
.SetValue("log", new Action<object>(Console.WriteLine))
;
engine.Execute(#"
function hello() {
log('Hello World');
};
hello();
");

Related

How to find a type by FQN in a solution?

I am writing a Rider/ReSharper nav-from-here plugin which is supposed to determine a target type based on a symbol I am standing on using some simple rules, and finally, navigate to it.
The first part is okay, I have managed to form the FQN needed, but I am struggling with the navigation. I found this StackOverflow post, and thought I might try this approach. So I have been trying to use TypeFactory.CreateTypeByCLRName for like two hours to create an IDeclaredType instance to be able to get the IDeclaredElement using GetTypeElement() and eventually get its declarations. But the API seems to have changed and no matter what I do I cannot get my code to work.
Here is what I've got so far:
// does not work with Modules.GetModules(), either
foreach (var psiModule in solution.GetPsiServices().Modules.GetSourceModules())
{
var type = TypeFactory.CreateTypeByCLRName("MyNamespace.MyClassName", psiModule);
var typeElement = type.GetTypeElement();
if (typeElement != null)
{
MessageBox.ShowInfo(psiModule.Name); // to make sure sth is happening
break;
}
}
The weird part is, I actually see a message box - but only when the tab with MyClassName.cs is active. When it is in focus, everything is fine. When it's not or the file is closed, the class does not get resolved, type.IsResolved is false.
What am I doing wrong?
To do this, you should have a IPsiModule instance from the context where you plan to use the type you're looking for. You can get it from some syntax node you're working with via .GetPsiModule() method or via many other ways (like dataContext.GetData(PsiDataConstants.SOURCE_FILE)?.GetPsiModule().
void FindTypes(string fullTypeName, IPsiModule psiModule)
{
// access the symbol cache where all the solution types are stored
var symbolCache = psiModule.GetPsiServices().Symbols;
// get a view on that cache from specific IPsiModule, include all referenced assemblies
var symbolScope = symbolCache.GetSymbolScope(psiModule, withReferences: true, caseSensitive: true);
// or use this to search through all of the solution types
// var symbolScope = symbolCache.GetSymbolScope(LibrarySymbolScope.FULL, caseSensitive: true);
// request all the type symbols with the specified full type name
foreach (var typeElement in symbolScope.GetTypeElementsByCLRName(fullTypeName))
{
// ...
}
}

How to build a .NET interpreter (or how does Powershell work?)

I am looking at creating a small interpreter for C# that I could load in some applications. Something that could be able to run things like this:
> var arr = new[] { 1.5,2.0 };
arr = { 1.5, 2.0 }
> var sum = arr.Sum();
sum = 3.5
And so I was thinking this could be achieved by creating a dictionary of all the variables and their types and then compile each of the row as they come, and then execute the function, get the result and stick it in the dictionary of variables.
However, it seems to me that this may be actually quite difficult to build and possibly very inefficient.
Then I thought that Powershell was doing what I needed. But how is it done? Can anyone enlighten me as to how Powershell works or what a good way would be to build a .Net interpreter?
How about you host the PowerShell engine in your application and let it do the interpreting for you? For example:
private static void Main(string[] args)
{
// Call the PowerShell.Create() method to create an
// empty pipeline.
PowerShell ps = PowerShell.Create();
// Call the PowerShell.AddScript(string) method to add
// some PowerShell script to execute.
ps.AddScript("$arr = 1.5,2.0"); # Execute each line read from prompt
// Call the PowerShell.Invoke() method to run the
// commands of the pipeline.
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(result.ToString());
}
}
If your goal is to learn how to build an interpreter, have a look at the interpreter pattern.
Look at either Roslyn http://msdn.microsoft.com/en-US/roslyn or Mono Compiler http://www.mono-project.com/CSharp_Compiler . Both should be able to do what you are looking for
Somthing like this? Or perhaps Roslyn(http://msdn.microsoft.com/en-gb/roslyn)
Added comment as answer, as it seems more useful than I first thought

how can I use js/coffee to screen scrape an asp page?

I've got a website that I'd like to pull data from and it's really stuck in the stone ages. There's no web service, no API and it's very much an ASP/Session/table-based-layout page. Pretty fugly.
I'd like to just screen scrape it and use js (coffeescript) to automate that. I wonder if this is possible. I could do this with C# and linqpad but then I'm stuck parsing the tables (and sub-tables and sub-sub-tables) with regex. Plus if I do it with js or coffeescript I'll get much more comfortable with those languages and I'll be able to use jQuery for pulling elements out of the DOM.
I see two possibilities here:
use C# and find a library that will do things like Jquery but in C# code
use coffeescript (js) and use jquery to find the elements that I'm looking for in the page
I'd also like to automate the page a bit (get next set of results). This is strictly for personal use -- I'm not pulling results of someone's search to use in my business. I just want to make a crappy search engine do what I want.
I wrote a class that allows you to supply a bunch of urls and a code block to scrape pages inside a chrome extension. You can find the github repo here: https://github.com/jkarmel/Executor. It could use some more testing and I need to work on the documentation, but it looks like it might be what you are looking for.
Here is how you would use it to get the all the links from a few different pages:
/*
* background.js by Jeremy Karmel.
*/
URLS = ['http://www.apple.com/',
'http://www.google.com/',
'http://www.facebook.com/',
'http://www.stanford.edu'];
//Function will be provided to exector to collect information
var getLinks = function() {
var links = [];
var numLinks = $('a');
$links.each(function(i, val) {links.push(val.href)});
var request = {data: links, url: window.location.href};
chrome.extension.sendRequest(request);
}
var main = function() {
var specForUsersTopics = {
urls : URLS,
code : getLinks,
callback : function(results) {
for (var url in results) {
console.log(url + ' has ' + results[url].length + ' links.');
var links = results[url];
for (var i = 0; i < links.length; i++)
console.log(' ' + links[i]);
}
console.log('all done!!!!');
}
};
var exec = Executor(specForUsersTopics);
exec.start();
}
main();
So basically the code to collect the links would be supplied to the executor instance and then you would do whatever you wanted with the results in the callback. It can deal with longish lists of url (~1000) and it will work on more than one at a time (default == 5). It doesn't handle errors in the code block very well right now, so be sure to test the code you are supplying.
I'm liking Curtain A) "use C# and find a library..."
"HTML Agility Pack" might be just what you're looking for:
http://htmlagilitypack.codeplex.com/
You can do it easily with Node.js, jsdom, and jQuery. See this tutorial (in JavaScript).

How to send JavaScript code to IE using C# (.Net 3.5), run it, then get a string return value from the JS code?

We are developing an application which needs to interact with the active document in IE.
Context: The app is a C#, .Net 3.5 desktop app. The goal is to highlight specific text elements in the web page on user request. For this we need to retrieve and interpret web page elements (the need for the return value) then act on them through another JS call. The operations that must be made in the web page are not all done at the same time so we must get some kind of "snapshot" of the interesting text elements (we do this on the Mac version of our app by returning a string containing an XML representation of those elements).
In .Net we used IHTMLDocument2's execScript method successfully to run some JavaScript inside the active IE document, but we can't seem to find a way to get a return value from the call. Based on the doc execScript returns an execution success/failure constant which is not what we need.
In essence what we need to do is to load some JavaScript from a text file into a string, then send it to IE for execution. Then we need to get a string back from the called script.
Any hints on what objects to use? How to proceed to get this functionality?
Thanks in advance!
My colleague found the solution, based on what Alun Harford said:
string jsToRun = "function myTest() { return document.title; } myTest();";
mshtml.IHTMLDocument2 myIHTMLDocument2 = GetSelectedIEWindow();
IE ie = IE.AttachToIE(Find.ByUrl(myIHTMLDocument2.url));
string jsReturn = ie.Eval(jsToRun);
jsReturn then contains the string value returned from myTest() in JavaScript. Note that there is no return before the myTest() function call in the script!
Have a look at the WatiN codebase. In there, IE.Eval does exactly what you're looking for.
If you are providing the html and script yourself you can do the following:
execute the javascript function
let the js function place the result in an html element
wait till the function is done running
retrieve the html element using document.getElementById
and retrieve the value
I'm not sure if there's a easier way to do this.
Well it is nasty but it can be done.
Try this:
[Guid("626FC520-A41E-11CF-A731-00A0C9082637"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
interface IHTMLDocument
{
void Script([Out, MarshalAs(UnmanagedType.Interface)] out object ppScript);
}
public object RunScript(InternetExplorer ie, string scriptText)
{
IHTMLDocument doc = (IHTMLDocument)ie.Document;
object scriptObj;
doc.Script(out scriptObj);
Type t = scriptObj.GetType();
return t.InvokeMember("eval", System.Reflection.BindingFlags.InvokeMethod, null, scriptObj, new object[] { scriptText });
}
That will return your value in the object (just cast to what ever type you expected). Of course .NET 4 makes this even easier ;)

Using PlotKit (javascript) through C#

I'm relatively new to Javascript, and although I know how to use it, I don't really understand the mechanics behind it. Bear with me here.
I need to write a small app that creates a chart (in SVG) based on data I take in as an XML file. I found PlotKit, which does exactly what I need, except that it's written in Javascript, while my current program is written in c#. I did some googling and found a few articles which explain how to evaluate simple Javascript code using the .NET VsaEngine class. Unfortunately, I have absolutely no idea how to use the VsaEngine to execute more complicated Javascript that requires references to other files. Basically, all I want is for c# to be able to call something like this as Javascript:
var layout = new PlotKit.Layout("bar", {});
layout.addDataset("data", [[0, 0], [1, 1], [2, 2]]);
layout.evaluate();
var canvas = MochiKit.DOM.getElement("graph");
var plotter = new PlotKit.SVGRenderer(canvas, layout, {});
var svg = SVGRenderer.SVG();
And get back the SVG string for the chart. I have no idea how to make it so that the above script knows where to look for all of the necessary objects. If I were to make a web page to do this, I would just add a few script headers referencing /plotkit/Layout.js, /plotkit/Canvas.js, etc., the Javascript would work fine.
If anyone could explain exactly how I would use PlotKit through C#, or could explain a more effective way to do this, I would really appreciate it.
EDIT: I realize I wasn't too clear with this question - I need my c# program to emulate a Javascript engine and use the PlotKit library without actually running a web browser. Is there any way to do this?
PlotKit is a JavaScript library that is intended to execute in the Client's Web Browser. C# is executed on the Server. To go about communicating between the two, you would render whatever data you wish to pass to PlotKit on the server and then output it in the HTML you send to the client.
So in your C# codebehind you would construct the JSON object that would be passed to PlotKit's addDataset method.
...
public partial class Default : System.Web.UI.Page
{
protected string PlotKitData = "[]";
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack) PlotKitData = GenerateJSON();
...
Then in your ASPX codefront you would have something like this.
<script>
var layout = new PlotKit.Layout("bar", {});
layout.addDataset("data", <%=PlotKitData%>);
layout.evaluate();
var canvas = MochiKit.DOM.getElement("graph");
var plotter = new PlotKit.SVGRenderer(canvas, layout, {});
var svg = SVGRenderer.SVG();
</script>
Perhaps ZedGraph might suit your needs instead?

Categories