Moving from AppleScript to Javascript for Automation (JSA)

Hi all,

I’ve hit a bit of a road block. I’m trying to figure out how to use JSA to script VoiceOver on macOS. I have small bits working, but other things are escaping me. I think the problem is that I just can’t work out how to translate AppleScript (and the info in the AppleScript dictionaries) to JSA in certain cases.

For instance:

tell Application "VoiceOver" output "Hello, world" end tell

In JSA works fine with:

var vo = Application("VoiceOver"); vo.output("Hello world");

But things start to fall apart if I try using other objects in the VoiceOver suite.

Applescript:

tell Application "VoiceOver" tell commander to perform command 'item chooser' end tell

…seems like it should be this Javascript:

var vo = Application('VoiceOver'); vo.commander.performCommand('item chooser');

I have tried a dozen different permutations on this and have spent way too much time searching for an answer. All the examples I’ve found, including those in the JSA Cook Book someone put together on GitHub, lead me to believe that I’m on the right track—but I just can’t quite get it.

If anyone can shed some light on this, I’d really appreciate it.

“Moving from AppleScript to Javascript for Automation”

Short answer:

I wouldn’t, if I were you. JXA is crippled, buggy, unsupported, and long dead. Tasks that work perfectly in AS may break in JXA and when they do there’s not a thing you can do. If you are able to remain on AppleScript (which is a not good language but at least works right and has a community of users happy to help when you’re stuck), that will be the least painful option for you by far.

Long, very boring, technical answer:

I’m pretty certain this is the problem command (your syntax is correct, FWIW):

vo.commander.performCommand('item chooser');

If that doesn’t work, it doesn’t work. And it wouldn’t surprise me if it didn’t: the Mac Automation engineers who wrote JXA had a surprisingly poor understanding of how AppleScript and the “AppleScriptable” apps it talks to actually speak Apple events. (Apple events are the OS-level messaging system that AppleScript uses to talk to Mac apps.)

Here is your original AppleScript, which I’ve tidied to better show its structure:

tell application "VoiceOver"
  tell commander
    perform command "item chooser"
  end tell
end tell

I will assume you have already tested this AppleScript and it works correctly, as expected, on your machine.†

The issue here, I wager, is that VO’s perform command command requires both a tell target and a string as a direct parameter. This is an unusual combination, but it is valid.

Normally when an application command is wrapped in a tell block, it takes the tell block’s target as its direct parameter when packing that command into an Apple event. However, this command already has a string as its direct parameter, so AppleScript instead packs that target object in a different area of the Apple event: its “subject” attribute (keySubjectAttr). And since AppleScript is the de facto standard as to how Apple events are spoken, the receiving app—in this case VoiceOver—knows to retrieve the command’s target object from that attribute.

What’s likely happening here‡ is the JXA engineers failed to implement this particular detail of Apple event/AppleScript behavior in JXA’s Apple event bridge: thus JXA can accept either a target object or a direct parameter, but not both. If your command needs both, you’re SOOL: JXA simply doesn’t support it.

If you really must use JavaScript, you can always install Node.js and try using nodeautomation:

#!/usr/bin/env node

const na = require('nodeautomation');

const vo = na.app('VoiceOver');

vo.commander.performCommand({_: 'item chooser'});

I don’t use/understand VO so I’ve not tested this code myself, but it is the direct translation of your original AppleScript. Note that nodeautomation’s syntax is slightly different to JXA’s, and also it is a bit rough and occasionally buggy. (If you do try it and it fails, let me know as it’s probably a bug I should fix.)

nodeautomation’s design is based on appscript (I wrote both, btw), and appscript achieved >99.9% compatibility with “AppleScriptable” apps by 2007, proving it can be done (though it did take several years and a lot of real-world testing and use by hundreds of users to get to that level).

However, I no longer provide (free) support for appscript, etc, which is why I recommend sticking with AppleScript if you can. While the AE/OSA/AS platform is the walking dead nowadays, out of all its ambulatory corpses AS is the least unsafe bet by a mile.

HTH


† I get an error -1708 when I run it; I suspect this is because I don’t have an “item chooser” available—whatever that is—and VO is being somewhat misleading on error codes. (-1708 means a command is not recognized, whereas VO obviously understands the perform command command but was unable to carry it out for some other reason.)

‡ I won’t bother running further tests to confirm this guess as there’s nothing we can do about it anyway: after JXA failed, Apple eliminated the entire Mac Automation department in 2016 and dumped the whole platform into minimal maintenance mode where it rots. But I am the world expert in this stuff so my guesses usually are.

2 Likes

I cannot thank you enough for this reply! The technical details were both interesting and helpful.

I didn’t realize that JSA had been essentially abandoned.

I have a background in a lot of languages, but neither AppleScript or Javascript are among those. I am marginally more familiar with Javascript, so I thought it might be the path of least resistance. I also thought, wrongly, that Javascript was the safer bet for the future.

In the end, either language is going to have some kind of learning curve for me. I’ll use AppleScript and hope that it sticks around for a while yet. I wish there was some sort of obvious successor to it, the way that Shortcuts is an obvious successor to Automator.

Thank you again!

Understandable: Apple don’t advertise the fact. (Which is just good business, if not very fair upon users.) AppleScript, JXA, and Scripting Bridge are all completely dead as products, 100% legacy-ware, and except for essential maintenance (security fixes, ARM builds) no new work is being done.

The difference is that, when put to bed in 2016, AppleScript was already very mature with all major features present and fully working, whereas the other two when they shipped (2014 and 2007 respectively) were half-baked and semi-broken and no effort was made to fix those problems in subsequent years (part of the reason they immediately failed so hard).

I would expect AS to “last better and longest” simply because it was built right, has lasted this long, and is the only one with a noticable user base. Which is why I say it’s the safest bet.

That said, I think it inevitable that AS usage will continue to fade, until Apple can finally, quietly pull the plug on whoever’s left. (A few print industry users that still haven’t made the jump to Adobe’s UXP, nobody else of note.) I suspect the sole reason they all remain now is because Apple can’t be bothered to do the extra work to take them back out. Still, it only needs one publicly embarrassing exploit and it’s Kobayashi Maru the lot.

All of which super sucks, as while AppleScript is a bad language, Apple event IPC (when it works right) is damn near pure awesome.

See above. I can’t see there ever being a successor to AppleScript itself, because Apple’s already tried this, twice, and both times failed hard. As far as they’re concerned, that’s because the tech is no good, so now they’re trying something else: Shortcuts, App Extensions. Technically it’s grossly inferior. But as long as it puts bums on seats, who cares?

1 Like

WB blame Zack Snyder and Ben Affleck, but they werent the problem. It’s WB who are just incompetent.

True dat. Still, fingers crossed… #BlackAdam