JXA problem — name of application

I am finally biting the bullet and starting to write JXA scripts. I have read (I think) every page in this forum describing how to get started with JXA, use JXA, debug JXA, etc., as well as many of the external references those pages provide. In fact, I’ve read a lot of these more than a couple of times. I have also watched the Apple videos. So I certainly think I should be ready to go.

I immediately stumbled on this, running in Script Editor:

Application('iTunes').name()
// "iTunes"
Application.currentApplication().name()
// undefined
Application.currentApplication()
// Application.currentApplication()

Explanation for the last two??

LOL. Of course, one of the first things you try is something I can’t answer. Sounds like a question for @ComplexPoint.

This works:

##jxa Script

'use strict';

(function run() {

var app = Application.currentApplication();
app.includeStandardAdditions = true;

// app.properties()
// --- RETURNS ---
// {selection: null, frontmost: false, class: "application", name: "Script Editor", version: "2.8.1"}

var propApp = app.properties();
var nameApp = propApp["name"];


//debugger;

return nameApp;

})();

###Result

"Script Editor"
1 Like

OK, but why is all that necessary? Am I fundamentally mistaken that the value of property prop of object obj can be gotten with

obj.prop()

and set with

obj.prop = new value

And why does

Application('iTunes').name()

work, but

Application.currentApplication().name()

doesn’t??

Yeah, I have a talent for that — for decades the first time I've tried someone's demo application I generally broke it within a few keystrokes. When exploring a new language or library I seem to aim about 80º off the norm and stumble over surprises right from the beginning. Later, I unerringly trip over strange behavior with things that should work.

I mean, why not? What could be simpler?

Same here! LOL.

Because that is the way Apple has designed JXA.
It's a small thing. Write yourself a JXA function to always get the name.

Maybe by design, maybe not — application behavior is of course not always intentional. Application is an Application, right? Why should name() not work with all of them?

Well, maybe JXA, or application dictionaries are inconsistent, or there is something weird about Script Editor as the current application.

Here's another one:

Application('iTunes').properties()['class']
// "application"
Application('Finder').properties()['class']
// undefined

The class of the Finder application is undefined?!? Come on.

This is making me nervous, not just from the point of view of confidence in JXA, but from the consideration of how much of my time I will have to spend tiptoeing around weirdness like this. I guess I will have to develop the same enormous catalog of special cases and workaround tricks that I did for AppleScript over the years.

That's up to you. I guess what makes a person "nervous" is unique to that person.

I'm not nervous or anxious at all about JXA. Every language has its shortcomings. JXA as of macOS El Capitan seems to work very well, at least for me. For any enhancements or workarounds that I might need, it is very easy to add JXA functions to a Script Library, which can be easily accessed by any JXA script.

JXA brings with it the powerful feature set of core JavaScript, which is a huge benefit/advantage over AppleScript, IMO. Having a powerful, but easy to use, RegEx facility built into core JavaScript is a huge benefit, all by itself.

Mitchell - You sound exactly like I did a few months ago. I got extremely frustrated because, like you, I couldn't decipher the logic behind some of the syntax for Automation stuff.

I strongly encourage you to not let that stop you. I was ready to storm Apple headquarters and ask them WTF? But I am so glad I kept at it.

Now, I have a library of JXA routines I use all the time.

I have a lot of it up on my GitHub repository. It's not as well organized as I wish, and there's some clutter, but that's life.

To anyone interested in learning about JavaScript for Automation (JXA), you might find this helpful:

###JXA Resources

Yes, I did find the resources helpful. I read/watched them all, some several times.

That is not my usual style — I like to dig in an experiment as I am learning, but it took me a while to wrap my head around JXA even thought I have been writing AppleScripts for ages and JavaScripts for a long time too. And done some Objective-C. Don't know what the problem is, maybe late life timidity.

Great! I'm glad you found it helpful.

Please feel free to offer any constructive criticism and/or suggestions that would help improve and/or extend this resource page.

I'm not sure that the Automation object is in good shape in the current build of Sierra – perhaps an interregnum in responsibility for macOS automation ?

but the value returned by the .currentApplication(); method depends, in any case, on the name space in which it executes – its value can vary, for example, between a global and a module level context, and it's up to the particular application object to implement a .name() method (or .name property).

(function () {
    'use strict';

    var a = Application.currentApplication(),
	sa = (a.includeStandardAdditions = true, a);
	
	return sa.properties();
	
})();
{"selection":Application.currentApplication(), "frontmost":true, "class":"application", 
 "name":"Script Editor", "version":"2.9"}

(Hard to think, incidentally, of a good reason for binding names in any global JS context - in the case of Automation object scripting, the global name space persists between script runs, so its quite easy to trip up on things left on the floor by previous global context runs. (A module context, in contrast, cleans up after itself))

Try, for example, running this piece of Sierra ES6 JavaScript twice in Script Editor (unwrapped in a module – anonymous function envelope):

    const a = Application.currentApplication(),
	sa = (a.includeStandardAdditions = true, a);
	
	sa.properties();

Runs fine the first time, but not the second ...

(The bare global context is really a bit too complex and over-crowded to be a helpful workplace)

Hey Mitchell,

Don't get too nervous until you look at the underlying objects:

tell application "Finder"
   set p to its properties
end tell

Note that class in the Finder's properties is null.

Note too that JXA doesn't like Finder-objects – at least for output:

Application('Finder').properties()['home directory']
// --> undefined

I don't know if that can be coerced into a path-string and then output, although I'm sure one of the JXA-crew does.

-Chris

Hi Chris, do you mean 'home' ?

AppleScript

tell application "Finder"
    
    home
    
end tell
--> folder "houthakker" of folder "Users" of startup disk of application "Finder"

JavaScript

(function () {
    

    return Application('Finder').home();
    
    // Or
    // return Application('Finder')['home']();
})();
//--> Application("Finder").startupDisk.folders.byName("Users").folders.byName("houthakker")

(Note, incidentally that no keys contain spaces in the JavaScript version of the scripting dictionary, so 'insertionLocation' rather than 'insertion location' etc:

PS, for the home path, I personally tend to write/paste:


$('~').stringByStandardizingPath.js

‘Class’ is an AppleScript property key and and element of the AS architectural lexicon.

In JavaScript you typically use typeof and instanceOf – that happens to be outside the scope of the Automation library object – just a difference in languages.

Note also that the .properties() method is just a useful convenience provided by some objects – it’s not the general or natural route to actual evaluation of methods and properties.

If you want to send me a forum mail, I can give you the current contents of my Quiver repository of JXA functions and their AS equivalents – should save a bit of time. Not really in publishable state, but perhaps useful day to day, and as a starting point.

(In ES6 format by default, but Babel JS back-translates)

Good idea — check the equivalent AppleScript when something weird seems to be happening.