Using Script Editor to test scripts for `Execute JXA` actions

With the default "Modern Syntax" option, Execute JavaScript for Automation objects provide a predefined kmvar for easy access to KM Variable values.

You can choose, from the menu behind the small chevron to the left of the code field, which key:value pairs are included in kmvar:

and then, in your script you can easily use the KM Variable values:


You can use Script Editor for sketching and testing JS snippets to use in Keyboard Maestro Execute JavaScript for Automation actions, but three things are worth keeping in mind:

  1. You are probably better off using Visual Studio Code, to get automatic code formatting etc (but Script Editor is a good enough start)
  2. To return a value from a KM action you have to explicitly prefix it with the return keyword (not needed in Script Editor)
  3. You will not find the kmvar object automatically pre-defined for you in Script Editor

Lets ignore point 1. and focus on 2. and 3.

Expand the following disclosure triangles to read the details:

The `return` prefix is needed for the action, but not for Script Editor

Adding the return keyword for the KM action, and removing it for Script Editor – this we probably just have to remember.

One way to handle it is to always wrap your Script Editor code in an "IIFE" – Immediately Invoked Function Expression – which is standard good practice anyway.

A minimum JS script without an IIFE might be:

const value = 2 + 2;

value;

But that hits problems the second time we run it. Declarations are remembered by the Script Editor JS Context between successive runs, and we will be told that you can't declare a constant twice.

Screenshot 2025-02-21 at 4.13.29 pm

We can fix that by using an IIFE-wrapped temporary name-space, which looks like:

(() => {
	"use strict";

	const value = 2 + 2;
	
	return value;
})()

Notice that it requires a return, or it will return no value to its context.

The use strict; incantation just switches on more helpful error messages.

If we run the IIFE version above in Script Editor, we see a computed value appear in the result panel:

If we copy-paste that code directly into an Execute JavaScript for Automation action we need to prefix the whole script with return, before KM sees a result:

But Keyboard Maestro is secretly wrapping our work in its own IIFE, so if we want we can now eliminate that for the action:

In practice, if I am moving back an forth between an action and a code editor like Script Editor, I find it easier to leave an explicit IIFE in place, and just:

  • add a return when pasting into the action, and
  • delete the return when I paste back into the code editor
No `kmvar` object is automatically pre-defined in Script Editor

To test a script in Script Editor, before using it in a Keyboard Maestro Execute JavaScript for Automation, we would like to be able to use the simple kmvar.Application_name and kmvar.activeLang etc format.

A trick that I often find useful is to:

  • temporarily declare a kmvar object (by copy-paste) at the top of the script in Script Editor or Visual Studio Code,
  • use it in testing, and then
  • comment it out before pasting into the Keyboard Maestro action

To get a JSON (JavaScript Object Notation) copy of the kmvar object:

  1. Select the variables that you want in the small chevron menu to the left of the JXA code field in the KM action
  2. return the expression JSON.stringify(kmvar, null, 2) from the action.

(The null means no special adjustments, and the 2 gives indents of two spaces)

This will produce a JSON copy of kmvar which you can paste into your script – something like this:

{
  "activeLang": "com.apple.inputmethod.SCIM.ITABC",
  "Application_name": "Mail",
  "backgroundColor": "[0.13330282270908356,0.13330282270908356,0.13330282270908356]"
}

prefixing it with const kmvar =

thus, perhaps, for Script Editor:

(() => {
	"use strict";

	const kmvar = {
  		"activeLang": "com.apple.inputmethod.SCIM.ITABC",
 		"Application_name": "Mail",
  		"backgroundColor": "[0.13330282270908356,0.13330282270908356,0.13330282270908356]"
	};
	
	return kmvar.activeLang;
})()

and correspondingly, for the KM Execute JavaScript for Automation action:

  1. prefixing the whole with return, and
  2. commenting out the explicit declaration of kmvar
return (() => {
    "use strict";

    // const kmvar = {
    //	"activeLang": "com.apple.inputmethod.SCIM.ITABC",
    // 	"Application_name": "Mail",
    //	"backgroundColor": "[0.13330282270908356,0.13330282270908356,0.13330282270908356]"
    // };

    return kmvar.activeLang;
})()

5 Likes

So that's how you do it! I've just been adding and removing a space to force a recompile/new context :wink:

And thanks for all the other nuggets in your post -- you just might have pushed me over the threshold and into JXAville...

2 Likes

Have fun !

1 Like

@ComplexPoint, this post is filled with so many helpful tips; thanks for sharing!

As you undoubtedly know, the variable selection process can be a bit tedious. In cases that include multiple variables, I do the following...

( expand / collapse )
  • Select the first variable in the list because: 1) it's easy, and, 2) as seen below serves as a placeholder.

  • Select the JXA, right click, and select Copy as XML.

  • Paste the XML into your favorite text editor. I normally use BBEdit.

  • Search for the IncludedVariables key and replace the placeholder variable with one of the variables needed for your JXA action.

  • Duplicate that line and modify the duplicates to include any additional variables needed.

  • Select All and Copy the modified XML and return to the KM Editor.

  • Select the original JXA action and Paste. The revised action will be pasted below.

  • Delete the original JXA action.


1 Like