Saturday, May 7, 2022

JXA’s Parenthesis Paradox

Dr. Drang:

Because the name of the process is what we want to return, name has to go last in the chain of calls, and it’s the one that gets the parentheses. We’re applying the whose filter to the processes, so it has to go after processes. The properties we’re filtering on (just visible in this case) are set up as a JavaScript object that’s passed as an argument to whose.

Suppose we had two criteria for our filter? Let’s say we want all the visible processes that start with the letter M (which will return just Mail and Messages). In AppleScript, it’s easy to add an extra clause:

tell application "System Events" to get the name of every process ¬
    whose visible is true and name begins with "M"

In JXA, the syntax gets nasty:

Application('System Events').processes.whose(
    {visible: true, name: {_beginsWith: "M"}}).name();

JavaScript is nicer for basic programming and data manipulation, but Apple event stuff is much nicer in AppleScript.

Update (2022-05-10): See also: JavaScript vs. AppleScript.

Update (2022-06-10): Dr. Drang:

Next, we move on to whether JavaScript for Automation (JXA) is worth getting into at all. Do AppleScript concepts really translate well to JavaScript? The same day my last post was published, Rosemary and David released their Automators episode with Daniel Jalkut. While discussing Daniel’s FastScripts app, they had a little sidebar about JXA. Daniel doesn’t think much of it. “It just shouldn’t be there” was his most pithy comment, but he also mentioned an “impedance mismatch” between the JavaScript language and the AppleScript infrastructure underneath it. Exactly.


Finally, let’s talk about the reason I’ve used JXA for some scripts: JavaScript has a good regex engine and AppleScript has none.


2 Comments RSS · Twitter

I obviously understand why Apple didn't go with Ruby, but there's some really nice ways you could support this in Ruby.
In Ruby, the optional parens make DSLs like this really nice to use.

While the query may be less efficient, there are unlikely to be so many processes that doing the data filtering in JavaScript wouldn’t be acceptable:

Application('System Events').processes()
  .filter((p) => p.visible())
  .filter((p) =>'M'))

Leave a Comment