How To Use "VS Code" for JXA, with Keyboard Maestro

So where do you do this? In Script Editor or Atom or VS Code, and then do you run and attach the script like in your video to Safari, and then see what is in kmProps in the Safari debugger?

That seems so painful compared to what is possible using the Python extension in VS Code.

I so agree that there has got to be some holy grail that @ComplexPoint say uses. He seems to be able to come up with scripts with such ease. Almost like play activity :slight_smile:

Of course, you are way advanced as well, with your macros, applescripts and frankly even JXA.

Many many thanks for your help and engagement.

So I figured that one way to do this is to launch the script in debug mode, and see the value of KmProps in the Safari debugger console.

1 Like

I'm not sure why you're having issues with autocomplete.

Make sure it says "JavaScript" in the bottom right:
image

Here's an example. I'm starting to enter PathNameUtils like where the arrow points, and you can see I get a completion list:

Now I'm starting to enter AddTrailingSlash, and it shows the property and its definition:

Once I type the opening paren, it shows parameter information:


There are some objects VSCode can't give you Intellisense for, like this:

var obj = { firstName: "Dan", lastName: "Thomas" };

If you pass it as a parameter to another function, VSCode won't know what it is.


However, if you have a class definition like this:

...and you start using it, VSCode will provide Intellisense:

If you pass it as a parameter into a function like this, VSCode doesn't know the definition of "paths":
image

But, you can create JSDoc comments for the function. Start by typing \** and hitting return:
image

Then modify the parameter definition to add the "type", as show by the red arrow, and now you get true Intellisense completion:

So basically, you have to give VSCode some way to infer the object type, if you want actuall Intellisense. Otherwise it just gives you a list of all the names it knows about.

Which isn't horrible, by the way, because you can type just a few letters to get the list filtered down, like here where I typed gfn:
image

There's tons of stuff like this. I know some of this because I used Visual Studio during my professional development career, and VSCode has a lot of similarities.

Oh, and regarding properties, I've never been able to figure them out like how Jim shows. So I just use a lot of console.log() messages along with JSON.stringify(). I'd rather do it like Jim mentioned, but I can't seem to remember to try it, and I just resort to the old tried-and-true methods.

However, when dealing with JXA automation objects, after a while you start to understand the naming conventions compared to AppleScript, and it gets easier.

Hope this helps.

1 Like

Thank you for the detailed reply. I will have to work through and absorb everything one by one.

I installed CodeRunner and also AppleScript extension. Language is Javascript at the bottom right of VS Code and checked by invoking cmd-shift-P and then lang and configured language is javascript. File name also ends in .js

However, I am not seeing any JXA related code completions. For example here:

.

And when I try and type the code that you have in your example, this is what I get.

Of course, I am doing something wrong. Are there extensions that I should check for, or any specific settings in VS Code.

I do have basic javascript code completion / intelligence in VS Code.

May be this is how it should be and the code completion that I am not seeing is a result of not importing some js library.

Thank you!

VSCode doesn't know anything about Automation objects, because they're not defined in your source file, so you won't get code completion on them. If someone wanted to take the time and effort to create an Intellisense JSON file for Automation objects, then you'd have it, but I don't see that happening.

See here for more information: https://code.visualstudio.com/docs/editor/intellisense, and the linked JavaScript section.

I installed CodeRunner and also AppleScript extension

Which is good, but they don't have anything to do with code completion. Well, that's not entirely true. The AppleScript extension gives some support for Intellisense with the AppleScript language mode, but that doesn't help with JXA.

And when I try and type the code that you have in your example, this is what I get.

Well, yeah, you don't have the class defined - it's a custom class of mine. I was just pointing out how it works with classes in general. Try a class like I showed (you can copy and paste this):

	class GroupPathNames {
		constructor(groupFileName, repositoryFolderPath)
		{
			this.groupFileName = groupFileName;
			this.groupFolderPath = repositoryFolderPath + groupFileName + "/";
			this.groupSourceFilePath = this.groupFolderPath + groupFileName + sourceFileExtension();
			this.macrosFolderPath = this.groupFolderPath + "macros/";
		}

		makeMacroSourceFilePath(macroFileName) {
			return this.macrosFolderPath + macroFileName + sourceFileExtension();
		}
	}

And then something like:

	var path = new GroupPathNames

and type the parens.

1 Like

Two more things:

  1. Make sure you read this: https://code.visualstudio.com/docs/languages/javascript. It'll give you a good idea of what features you're getting.

  2. Regarding Intellisense for Automation objects, someone has created something for TypeScript/Node.js that has Intellisense definitions for JXA, but I have absolutely no idea how to use it. So don't ask me. :stuck_out_tongue: But if you figure it out, feel free to post it here.

Thank you for the message again. I did what you advised, and I have the auto complete working.

So I guess as far as the setup of VSCode and running JXA files (saved as js files) using Code Runner, I am all set. Thank you! I know it is repetitive, but so be it.

From an earlier message of yours - so say I create myApp like so var myApp = Applications("Keyboard Maestro"). Is there a way to inspect myApp in Safari console? I tried console.log() and JSON.stringify(). Neither seem to work. Nor does console.dir() which Safari reports is not even a function.

I did read this article. Will read again though as I am a newbie, especially with javascript and of course JXA.

I tried it by cloning his repository. But then I quickly realized that I do not know enough javascript to understand all the structure that I need to create. May be will get there in some time and will try to use it again. I wonder though as to why you have not attempted it, or perhaps it is that you attempted it and did not find it that useful.

Thank you!

Awesome, and I'm glad you got it working!

From an earlier message of yours - so say I create myApp like so var myApp = Applications("Keyboard Maestro") . Is there a way to inspect myApp in Safari console?

I don't know. It doesn't seem like it. But you can open the Dictionary in Script Editor and change the Language to JavaScript, and get the definitions from there.

But then I quickly realized that I do not know enough javascript to understand all the structure that I need to create.

Yeah, it was over my head for now. I mean, I'm sure I could figure it out, but it just looks like too much work. :smile:

I've got some JXA scripts that might help. I haven't reviewed them in several years, so while I assume they work, nobody likes the code they wrote a couple of years ago, right?

If you have questions, just ask. Have fun!

1 Like

Thank you for the link. Yes will go through the scripts that you created. And I know what you mean that one does not want to look at one's own old code. :smile:

Quick question on how you do the above. So where do you use console.log or JSON.stringify() to look at what inspect JXA objects?

This is the big issue that I am facing right now. Perhaps I need to start another thread and ask as to how to best interpret and use the Dictionary in Script Editor. May be, if I can interpret the dictionary better, then I will feel less need to inspect JXA objects...

I totally, 100% agree with how frustrating it is. If you go back a few years you'll find some posts from me, where I'm, um, "complaining" to anyone who'll listen about why is this so hard to figure out?

As far as I know, you can't use console.log() to find out the properties of Automation objects.

As for how to use the dictionary, it's easy, if not a little frustrating.

  1. Start Script Editor, and click the "New Document" button in the bottom left.

  2. Click "File->Open Dictionary".

  3. Select the application, like "Keyboard Maestro Engine".

  4. At the top middle is the "Language", which probably defaults to "AppleScript". Change it to "JavaScript".

Then you have to start looking around, but for the KM Engine, try clicking on the "Keyboard Maestro Engine Suite", and in the second column, you'll see some of the functions and objects available.

But in my opinion, it's easier to find examples and just learn from them. Like my scripts I linked to, or search this forum for specifics.

Also, don't forget these links:

I'm pretty sure @JMichaelTX has a bunch of resources listed somewhere, too.

My best advice: Get frustrated, don't get frustrated, either way, don't give up. If it happens to you like it happened to me, one day you'll want to tear your hair out, and the next day it suddenly starts to click.

2 Likes

You can if you first convert the objects to a JSON string, then log that.

1 Like

Thanks for the encouraging words and the help and the links. At this point, I am trying to Automate some things with OmniFocus app. The Script Dictionary concepts that I need to understand are basic concepts however.

I am guessing it is best to start another thread for that.

That would be wonderful. Please don't hold back as to how to do that. That would be huge!

See JSON.stringify() .

Got this. However, can this be used on JXA objects? That does not seem to work for me.

So, when running a JXA script which is in debugger mode and in Safari debugger and halted,
then after running
myApp = Application("Keyboard Maestro");,
executing
JSON.stringify(myApp); in the Safari console results in undefined as output, and console.log(JSON.stringify(myApp)); does not generate any information either.

I think Jim means something like this:

var kme = Application("Keyboard Maestro Engine");
var kmeProps = kme.properties();
console.log(JSON.stringify(kmeProps, null, "\t"));

But that doesn't return much information:

{
	"frontmost": false,
	"pcls": "application",
	"name": "Keyboard Maestro Engine",
	"version": "9.0.2"
}

You are right. He had earlier mentioned that he uses kme.properties() to inspect, and then make a string of it and then print it. Got it.

And as you rightly observed, this does not give the full extent of what is available with the kme object.

Thank you both!

OK, this is interesting. I'll explain the steps I took in a second, but look what I've got here. I've got my cursor over "Application", and I've got Intellisense:

image

And I guess I've got Intellisense for the following applications (I stitched two screenshots together to get the entire list):
image

Here's what I did. I started here: https://github.com/JXA-userland/JXA/issues/4

Interestingly enough, @JMichaelTX had asked some questions, and one of the answers led me to here: https://github.com/JXA-userland/editor-integrate-example

I followed the steps he listed, and I'll add a couple of notes:

  1. I created a folder called Test (not totally relevant, but it's what I did).

  2. Opened a Terminal window inside the Test folder.

  3. I executed the first step from the above "example" link:
    git clone https://github.com/JXA-userland/editor-integrate-example
    It worked, and created a subfolder called editor-integrate-example with some stuff in it.

  4. Next step from link:
    cd editor-integrate-example

  5. Next step:
    npm install

    This failed with a bizarre error because my node or npm installation(s) were messed up (I don't know a lot about this stuff), but some searches led me to this solution, which worked because fortunately, my installation of homebrew is NOT messed up:

    brew uninstall --force node
    brew uninstall --force npm
    brew link --overwrite node
    
  6. Next step:
    vscode .
    But it couldn't find vscode, so I must not have my path set correctly for VSCode from the command line. So I did it this way:

  7. Opened VSCode the normal way, then:

  8. File->Close Workspace

  9. File->Add folder to workspace

  10. Added the folder that had been created in my Test folder, editor-integrate-example.

  11. Opened the file example-jxa.js.

  12. Hovered my cursor over the Application object, and presto! Intellisense! It looks kind of different, but there's certainly good info there.

Here's some thoughts:

  • Either package.json or tsconfig.json are probably what's telling VSCode where to get the Intellisense files. I'm guessing it's package.json because I think the other one is for TypeScript.

  • I have no idea where to put this stuff so it's accessed automatically from other JXA projects.

  • No Intellisense for any other applications, like "Keyboard Maestro", etc. However, if you delve into the source files, I can't believe he typed them all by hand, so I'm guessing there's a way to import a Dictionary entry to create these files. If so, then someone could create them for "Keyboard Maestro", etc. But I don't have the time to spend on it now, so it's up to you guys, or nobody. I've got a video I have to finish, and then some "honey-do" projects, so that's as much time as I can spend on this. I'm telling myself this, also. :slight_smile:

I followed your steps and indeed it works. I had stumbled on it earlier also but must have missed some step. Thank you!

:rofl: I know exactly what you mean.

1 Like

Here are two links that I reached which seem to source Intellisense for other apps. However, 1) the discussion appears to be for Typescript, and 2) most of it I am not able to understand.

Sounds like one has to convert “sde” to “dfs”. More generic discussion as to how to add support for other application is here.

Somebody would know how to make it work... or maybe, once I understand more javascript.

1 Like