Debug dynamically loaded JavaScript code with IntelliJ and the Nashorn engine - javascript

I am dynamically loading and running JavaScript code that is stored on disk in a YAML file. I would like to know if it is possible (using intelliJ) to debug the JS code even though I am not loading it from a standalone JS file. To simplify the problem description, consider the following Java code:
NashornScriptEngineFactory nashornFactory = new NashornScriptEngineFactory();
ScriptEngine engine = nashornFactory.getScriptEngine();
engine.eval("var a = 1 + 1;\nprint(a);");
How do I set a breakpoint on line two (the "print" function call) and how do I examine the value of variable "a"? If this is not possible, what would be the best workaround?

Based on this blog post https://blogs.oracle.com/sundararajan/remote-debugging-of-nashorn-scripts-with-netbeans-ide-using-debugger-statements, you can just attach a remote java debugger to process.
You can do this in IntelliJ IDEA by creating a new remote run configuration.
After attaching, use the JavaScript command:
debugger;
This will force the debugger to break if it is attached. You can then inspect the values of variables within the variable window.
If you can't manage to attach IntelliJ, open the browsers inspector/debugger and this same line of javascript will cause the browser's debugger to break on that line.

Related

Chromium console.error internal implementation - what makes hyperlinked path to files in error stack?

I noticed that error stack visible while using console.error has ability to make URIs hyperlinked. Such formatting takes place as well in browser Devtools as in IDE i use (WebStorm with integrated Git Bash terminal).
Example screen (this comes from Jest testing framework, but such hyperlinks are also provided in usual console.error calls):
As Node.js uses Chrome's V8 JS engine under the hood, i have tried to debug console.error internal implementation, but i hit the wall at this line of code - it uses stream to output the error message, which beforehand is just a string without any special formatting (except new lines) and afterwards becomes formatted output in console (including hyperlinks). I don't know what happens below there.
The Console.prototype.error method seems to be created by assigning Console.prototype.warn method to it, which is confusing. Also, Devtools console's inspect function won't navigate to the implementation of console methods while debugging Node.js, even despite the fact that Node's code is more accessible than the browser's one - i mean it's possible to debug Node's internals to some level, which is not a thing in the browser.
My question: is it possible to output hyperlinked content (my intention is to hyperlink path to a module) to the console output in a controllable way?
That question arised, because i am writing a Node.js wrapper on console methods i use in project and, as i had noticed the hyperlinks to files in call stacks, i wanted to use that feature inside my wrapper. I know there are libraries that wrap console and offer a ton of features, but i want to have a tiny wrapper, with just one or two features included. If somebody knows library that offers such controllable hyperlinking to the console output, i'd appreciate sharing a link, so i could look up for it's implementation.
IDE
As others have already mentioned in comments: links are a feature of the IDE/Text Editor. You can provide a file path, but it may not be clickable depending on your IDE/Text Editor. E.g., console.error(`${__filepath}:${line}:${column}`)
Browser (Chromium Based)
Yes, this is possible to some extent. Just prefix the file path with file:///.
// index.js
const line = 2;
const column = 9;
console.error('ERROR: ', `file:///${__filename}:${line}:${column}`.replace(/\\/g, '/'));
console.log('done'); // set a breakpoint here inside of devtools
Run node --inspect-brk index.js
Open chrome://inspect
Select Open dedicated DevTools for Node (this will make sources visible in Devtools > Sources > Node) or inspect under the node process.
Allow the code to run to your breakpoint. Check the console and click the link
NOTES
replace(/\\/g) will make sure the path is valid (at least on Windows)
This is one of the rare places that file:/// links work in the browser.
You could also generate sourcemaps and link to the sourceMappingURL
https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map

Is it possible to make and run changes in javascript files using chrome developer tools or firebug without refreshing?

I am working an issue and problem is code is huge and deployed on some remote location and takes a lot of time to go through this process. Now, I know that in chrome developer tools we can open javascript files and modify/save them but problem is, changes are not reflected in application. for example, hello.js has something like this,
sayHello : function() {
// some existing code here.
}
now, developer tools allows to modify this file to look like,
sayHello : function() {
// some existing code here.
// additional code added at runtime.
}
but problem I am facing is, this additional code is not reflected when I execute
sayHello()
function again.
Note: I am not trying to load any new script here.
It's hard to say without some more input on your action, but could be that you are changing the source code (in the browser cache) and you expect the object already in memory to change as well? In case put a break point before the object is instantiated and change the code at that moment and see what happens.

In chome debugger, how can i load the variables names

Debugging javascript in chrome, how can i change the names of the variables in the debugger (_17, _18...) for the real names of the variables in source code?
if (_17) {
try {
var _18 = _17(_c);
if (_18 && typeof _18.then === "function") {
_18.then(_6.hitch(_16.deferred, "resolve"),
You need to use source maps when you build your code, then hook them up properly. That's what'll tell Chrome (and other modern browsers) what the real code is and it should link it up for you.
How you generate source maps depends on exactly how you build and minify your code.
Whatever minifier/compressor you're using should have an option to produce a "source map" which can be used, along with the original pre-minified source code, to allow you to debug while looking at your original source code even though the browser is running the minified version. If the map exists and is alongside the generated .js file, Chrome will pick it up automatically.
That said, normally you wouldn't minify source code during development.
More about Chrome's support for source maps here.
You can click with the right button in a variable that has been logged and save it to use as a temporary local variable.

Using third-party JS libraries in Mozilla Add-On SDK

I'm starting a new project (Firefox add-on) and I'd like to try using behavior-driven development. I particularly like the Jasmine BDD library. However, I can't find a good way how to use a framework such as Jasmine in the Add-On SDK.
One problem is that Jasmine needs setTimeout (and similar) functions to be specified on the global object, whereas Add-On SDK exports those using "timers" module. But let's say I tweak Jasmine to get those object from "timers" (or add the the methods exported by timers to the global object).
The bigger problem is that I don't know how to actually run the tests. There is a test directory generated by the SDK, however, there's no window or document object there to allow me to see the output (and I'd really like to see the fancy HTML output). I guess I could create a content script that would modify the page, but then I can't access (test) the background script.
Have you ever faced this before? Is there any recommended way how to deal with that?
Thanks!
Tomas
You can use the Add-on SDK windows API to open a new window to run your tests in. You should be able to load the Jasmine script(s) with the subscript loader and set window and document to whatever you want in the scope of that subscript:
var windows = require("windows").browserWindows;
windows.open({
url: "about:blank",
onOpen: function(window) {
var script;
var scriptLoader = Cc["#mozilla.org/moz/jssubscript-loader;1"].
getService(Ci.mozIJSSubScriptLoader);
scriptLoader.loadSubScript(subscriptSpec, script);
script["window"] = window;
script["document"] = window.document;
// ... run your tests here by calling script.someFunc() ...
}
});
Update: Further research shows that the browserWindows are actually special wrappers that don't give you access to the content window. You might try getting a window/document from a hidden frame. That's the only way I can see to get access to an HTML document from privileged code.

Is it possible to execute JSX scripts from outside ExtendScript?

Typically when you're writing a .jsx script to automate an Adobe product (like InDesign, Illustrator or Photoshop), you write, debug and execute the script from the ExtendScript IDE. Is it possible to bypass ExtendScript and run the script from a third program?
I think Adobe products have a built-in JavaScript interpreter which ExtendScript can connect to to access the Adobe object models and automate their software. I'd like to be able to connect directly to that interpreter and run jsx files just as I would in ExtendScript.
Are you on a Mac? If so, you can use AppleScript with the osascript tool to execute your JavaScript. Here are some examples:
Running JSX and Returning a Value
Save this as ~/temp/foo.scpt:
tell application "Adobe Illustrator"
-- 'do javascript' runs any arbitrary JS.
-- We're using the #include feature to run another
-- file. (That's an Adobe extension to JS.)
--
-- You have to pass a full, absolute path to #include.
--
-- The documentation alleges that 'do javascript'
-- can be passed an AppleScript file object, but
-- I wasn't able to get that to work.
do javascript "#include ~/temp/foo.jsx"
end tell
And save this as ~/temp/foo.jsx:
var doc = app.activeDocument;
var numLayers = doc.layers.length;
// The last value in the JSX file will be printed out by
// osascript.
numLayers;
Now, from the command line run osascript ~/temp/foo.scpt It will print the number of layers in the active Illustrator document.
Getting data out of the JavaScript is limiting. You can't print to stdout from within the JavaScript. Instead, place the value you want to return as the last statement of the JSX file; it will be printed by osascript. (Here's why: The last value in the JSX file is the return value of the do javascript AppleScript statement. That is also the last value in the AppleScript file, and osascript prints the final value.)
The value you return from JavaScript can be a number, a string, an array, or anything else that retains its value when converted to a string. If you want to return a complex object, you'll need to #include a JSON library and call .toJSONString() on the object.
Passing Arguments to JSX
To pass arguments to the JSX code, follow this example:
File ~/temp/args.scpt:
on run argv
tell application "Adobe Illustrator"
set js to "#include '~/temp/args.jsx';" & return
set js to js & "main(arguments);" & return
do javascript js with arguments argv
end tell
end run
File ~/temp/args.jsx
function main(argv) {
var layer = app.activeDocument.activeLayer;
app.defaultStroked = true;
app.defaultFilled = true;
// Top, left, width, height (in points).
// Note that parameters start at argv[0].
layer.pathItems.rectangle(argv[0], argv[1], argv[2], argv[3]);
}
And then run osascript args.scpt 50 30 10 80
Debugging
The do javascript command also has options for launching the ExtendScript debugger. For details, open the Illustrator dictionary in AppleScript Editor.
For Windows users, you can use a vbs script. Pass arguments to the .jsx script by providing arguments to the cscript command like so: cscript test.vbs "hello". test.vbs could look like so:
Dim appRef
Dim javaScriptFile
Dim argsArr()
Dim fsObj : Set fsObj = CreateObject("Scripting.FileSystemObject")
Dim jsxFile : Set jsxFile = fsObj.OpenTextFile("C:\Users\path\test.jsx", 1, False)
Dim fileContents : fileContents = jsxFile.ReadAll
jsxFile.Close
Set jsxFile = Nothing
Set fsObj = Nothing
javascriptFile = fileContents & "main(arguments);"
Set appRef = CreateObject("Illustrator.Application")
ReDim argsArr(Wscript.Arguments.length-1)
For i = 0 To Wscript.Arguments.length-1
argsArr(i) = Wscript.Arguments(i)
Next
Wscript.Echo appRef.DoJavaScript(javascriptFile, argsArr, 1)
The Wscript.Echo will return the last line returned by the .jsx file. A .jsx file example could be:
function main(argv) {
alert(argv[0]);
return "test";
}
When ran, you should seee Illustrator (or whatever adobe program) alert "hello" and then "test" will be returned to stdout (you should see it in the command prompt window).
This works in windows:
"C:\Program Files (x86)\Adobe\Adobe Photoshop CS5\Photoshop.exe" C:\completepathto\my.jsx
Pay attention to the path to Photoshop. It must be quoted since it contains spaces.
There are plenty of tricks for figuring out where Photoshop is loaded. Here is one that finds every location where Photoshop has been loaded and places those in x.lst
#REM The Presets\Scripts doesn't really restrict where the loop is looking,
#REM thus the "IF EXIST" is needed. The FIND makes sure that the
#for /R "%ProgramFiles(x86)%\Adobe" %%f in (Presets\Scripts)
DO #IF EXIST %%f
(echo %%f | FIND /I "Adobe Photoshop C" >> x.lst )
You can then process each line in x.lst. NOTE: The entire "#for" should be on ONE line, I split it to multiple lines for readability.
If you believe there will be only one Photoshop (and not Elements) then you could change
"echo %%f"
to
"%%f\..\..\Photoshop.exe" C:\completepathto\my.jsx
The straight answer is YES. Illustrator, InDesign and Photoshop can all be scripted through COM. Any program that you make that can access COM (such as a .net language, C++, BCX, Autohotkey or Powerpro) can tell Illustrator, InDesign or Photoshop to do things.
Here is an example for Powerpro(you will need powerpro's com plugin), and this works in CS4 and CS5:
Function ComLoad() ;;MAKE SURE TO CALL .#ComUnload WHEN EXITING FUNCTION CALLS!
static objname="Illustrator.Application"
static com_status, com_type
static appRef=com.create_object(objname)
endfunction
Function ComUnload();;this is end the com calls and unload com
com.unload
endfunction
After you use the ComLoad() function, you then run any kind of method or function offered by the COM library. Here is how to use Powerpro to tell Illustrator to run your jsx or js file:
;Run a script from anywhere
Function RunOtherScript(whatscript)
If (file.Validpath(whatscript) == 0)do
messagebox("ok","Whoops! That script doesn't exist!","ILL Runscript")
quit
endif
.#ComLoad()
appRef.DoJavaScriptFile(whatscript)
.#ComUnload()
quit
Here is an image of a floating toolbar that I made using Powerpro. The buttons are all attached to com functions. Most of the time I use the com functions to run external jsx scripts.
[edit]
There is another way! You can use the Adobe Configurator to create new panels which are capable of launching scripts. You can design the panel in any way you like, and the results are quite similar in effect to the powerpro toolbar I've described above. In fact, I moved from the powerpro toolbar to an Adobe Configurator Panel.
If you place the .jsx files in the right location
Photoshop
folder location:
/Applications/Adobe\ Photoshop\ CS5/Presets/Scripts
menu location:
File > Scripts
Illustrator
folder location:
/Applications/Adobe\ Illustrator\ CS5/Presets.localized/en_GB/Scripts
menu location:
File > Scripts
InDesign
folder location:
/Users/{user}/Library/Preferences/Adobe\ InDesign/Version\ 7.0/en_GB/Scripts/Scripts\ Panel
menu location:
Window > Utilities > Scripts
These are the paths on OSX, it should be easy to find the equivalent on Windows for Photoshop and Illustrator, but for InDesign it might be easier to open the Scripts Panel and open the scripts folder using the Panel's context menu.
I know that you can run .jsfl scripts from the command line by opening Flash and passing the path to the .jsfl script as an argument, but that doesn't seem to work for .jsx files with InDesign.
HTH
This question is quite old. I am going to answer this on the assumption that:
You're running JSX scripts for after effects.
You're using Windows.
I'm not sure whether you want to pass arguments to a script (in which case my simple solution won't work, or might need nasty workarounds).
Fortunately there is an easy way to do this with after effects. You can launch cmd and type the following command:
afterfx -r C:/Users/me/myscript.jsx
If afterfx isn't recognized, you'll need to add the after effects installation path to Path in your System Variables. I'm not aware of the availability of this feature in other Adobe programs.
For more information about running your after effects scripts from the command line, you can consult: https://helpx.adobe.com/after-effects/using/scripts.html
You can use extend script to run it .
there is a free extension on creative cloud will help you to run scripts fast in illustrator , aftereffects, photoshop and premiere pro
you can find it on adobe exchange ( liveview )

Categories

Resources