JXA: Is it ready for Prime Time?

I've noticed a number of very serious complaints about JXA in the Stackoverflow.com forum, suggesting that it is very flawed.

I'd be very interested in hearing from any of you that have significant experience in using, or trying to us, JXA. Are you seeing the type of issues described below?

I had hoped to move from AppleScript to JXA, since I prefer the general syntax of JavaScript over AppleScript. But now I'm wondering if this is a wise move.

Here's an example from Stackoverflow:

##JXA Issues

Like Leopard's Scripting Bridge before it, JXA intentionally breaks all sorts of stuff that works perfectly in AppleScript. Here is the translation of your original AppleScript command to JXA syntax:

 //tell application "System Events" to name of items in folder "/usr"
 Application('System Events').folders.byName('/usr').items.name()

The AS version works perfectly, but the JXA equivalent just throws a completely meaningless Error -1700: Can't convert types.

JXA does seem to work if you write diskItems instead of items:

Application('System Events').folders.byName('/usr').diskItems.name()
 // --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]

which suggests JXA indulges in much the same internal "cleverness" that causes SB to break on so many apps. (Note that I found numerous such design defects in earlier testing, but gave up reporting them once it was clear the AS devs only cared about imposing their own personal ideology and prejudices on everyone else, crippled capabilities and broken compatibility be damned.)

And so it goes. (e.g. Try testing JXA's support for range, filter, relative, and insertion reference forms; it's particularly rotten.)

I haven’t had any problems with it at all. Somebody seems to have been a bit disappointed that their own scripting bridge was not adopted by Apple – I’m not sure what the technical or other arguments were.

I think you will find that the comments are fairly consistently from that single source. As it happens, they don’t correspond to my experience of JXA, but they can sometimes make it a little hard to use StackOverflow for any question at all connected with JXA without provoking another recital : - )

( Whether the alternative scripting bridge would have been able to use the Safari Webkit debugger, as JXA can in 10.11, I don’t know, but that is one of the strongest features for me. My impression is that the other approach may have involved use of some libraries which Apple, for better or for worse, now considers superannuated).

Thanks Rob. That's good to know.

Every now and then I run into some issues.

For example, getting a list of every window of DEVONthink works fine with the AppleScript expression get every window, whereas Application('DEVONThink Pro').windows() just fails with a no apparent reason.

On the other hand, accessing DEVONthink windows works when using the appropriate subclass, e.g. Application('DEVONThink Pro').viewerWindows()

PS: turns out there is a another window class in DEVONthink which includes all windows. Using Application('DEVONThink Pro').thinkWindows() returns a list of every open window.

I think you may find that that has less to do with JXA than with the particular design of the DEVONtechnologies library.

I'm not sure I understand this. If the AppleScript code works, shouldn't the equivalent JXA code work? My understanding is that the developer's underlying code is the same. The only difference being the AppleScript or JXA bridge (both provided by Apple) to that code.

A perfect example is the Clipboard info functions.
AppleScript works great:
set lstCBInfo to clipboard info

whereas the JXA code returns "undefined" for most types:
app.clipboardInfo()

This is clearly a failure on the part of JXA.

No, I think the DEVONthink issue will probably need to be fixed on the DEVONthink side.

( It will be a minor compliance complexity arising from the the variety of subclasses that they use. )

A perfect example is the Clipboard info functions.

Reading the clipboard types through OSAscript is clearly out of JS reach at the moment, better to use the JS ObjC interface, but I think one would be hard pressed to call that an 'example' of anything more general. It's a very particular and specific question of how one would represent the legacy 4-char aete codes within the JS semantic model. The most sensible answer may be not to bother : - )

One always needs to reach for the right tool for the right purpose. In my case I find that it's more often JS than AS.

So why does the AppleScript work, but the JXA does not?

I don't understand. It's all Apple code. They both use the StandardExtensions to get the Clipboard info.
AppleScript works. JXA does not. Seems like a clear example to me.

Whether or not this is an isolated issue remains to be seen.

Well, we’re drifting away from KM issues here.

( I think if you lift the hood and see what’s going on behind these compatibility issues you may find that it’s not quite as clear as one imagines from the passenger or driving seat : - )

More broadly, however, I think what you may really be experiencing is that JavaScript for Applications is not (yet ?) as well supported with books and learning materials as AppleScript, which has a long established ecosystem, and which benefited from the easier past of the book publishing market.

That could in itself be a reason for using AS, though I personally encounter more technical frustration (lack of introspection in records, lack of higher order functions, compilation crankiness once program code gets to significant scale) with AS than with JS, despite having used AS fairly intensively for many years, and having had a lot of fun with it.

The great thing about Keyboard Maestro is that it supports both : - )

Perhaps. But I think it is beneficial to all to know what the limitations of JXA are when using a script with KM. Perhaps it's better to stick with AppleScript in KM until Apple has ironed out the JXA bugs.

No doubt. But I thought the point of AppleScript , and now JXA, is that we can be more like drivers, plotting our routes, rather than mechanics trying to get engine power to the wheels. :wink:

Don't get me wrong. I'm not trying to slam JXA. OTOH, I'm not going to sugarcoat it either. It's better for all when we can understand the bugs and limitations of any software, including JXA.

Perhaps you have already found all of the potholes in JXA, and now easily navigate around them without even thinking about it. :wink:

I’ll believe in them when I see them : - )

( but the documentation and learning materials are clearly not rich yet )

1 Like

Incidentally, it’s probably helpful to understand that JavaScript for Applications consists of two things:

  1. JavaScriptCore (JSC) (the same JavaScript engine as Safari)
  2. Some library objects – particularly Application and ObjC

That disgruntled voice on StackOverflow is more narrowly preoccupied with the technology that was chosen for the Application object, not with the JavaScript itself.

JavaScript engines like the JSC in JavaScript for Applications are very highly optimised, and get extremely intense use by millions, in a rather competitive environment, every day. You might be quite hard pressed to find a ‘pothole’ there : - )

As for the level of investment that Apple makes in further development resources for the Application and ObjC library objects - that will depend on the level of use. If you want it to develop, then use it …

The JavaScript engine itself is already excellent, and is assured of fairly high levels of ongoing development resource, simply because of its role on the web, and its competition with Chrome V8.

I suppose your #2 is what Apple calls the JavaScript AE Bridge:

I have no doubt that the JSC is solid.
Perhaps the JS AE Bridge still has some rough edges that need fixing.

BTW, as I was watching the JavaScript for Automation video from the WWDC 2014 this morining, I was reinspired to use JXA. It has a lot of promise.

A footnote: the JXA route to clipboard types turns out to be:

ObjC.import('AppKit');

$.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types

Which returns an array which can be unwrapped with ObjC.unwrap(). E.g.

$([$("public.utf8-plain-text"),$("public.html")])

( Thanks to http://stackoverflow.com/users/45375/mklement0 for this )

Thanks, Rob.

So, can you print a list of types on the current clipboard using this?

That's a link to his profile. Do you have a link to his post?

This:

ObjC.import('AppKit');
var arrCBTypes = $.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types
console.log(arrCBTypes[0])

yields this:

/* undefined */
Result:
undefined

So I guess I don't know how to use the code you provided.

So, can you print a list of types on the current clipboard using this?

Yes, that's the example shown in the previous post:

$([$("public.utf8-plain-text"),$("public.html")])

If you want all elements reduced to JS data types, you can use unwrap or deepunwrap:

(function() {
    'use strict';

    ObjC.import('AppKit');


	return ObjC.deepUnwrap(
		$.NSPasteboard.generalPasteboard.pasteboardItems.js[0].types
	);

})(); 

// e.g. --> ["public.rtf", "public.utf8-plain-text", "public.utf16-external-plain-text", "dyn.ah62d4rv4gk81n65yru", "com.apple.traditional-mac-plain-text", "dyn.ah62d4rv4gk81g7d3ru"]

mklement0's note is at the end of this thread: