By the way, you'll want to install the package linter-jshint, and follow the instructions in this note, above.
This is something you'll end up turning on and off as you work. But it's invaluable in helping catch errors, and also to teach you "proper" JavaScript (not that I know "proper" JavaScript but I'm learning, especially with tools like this).
And I find the package "command-toolbar" to be great for things like being able to toggle linter on and off. (I have it configured along the top, instead of the side):
I am missing something here. A brief example file would help. I have been using Atom to execute code in other languages, including AppleScript, but I can’t get even alert("OK") to work using JS or JXA grammar. I have many packages installed, and I’ve made the change to linter-jshint you showed above.
Where does the JavaScript context come from when executing in Atom? How does it know about Objc, $, etc.?
(function(inDesignMode) {
'use strict';
function execute() {
var kme = Application("Keyboard Maestro Engine");
var lastResultButton = kme.getvariable("Result Button");
console.log("Last 'Result Button' value: '" + lastResultButton + "'");
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var appSupportPath = app.pathTo('application support', { from: 'user domain' });
console.log("App support path: '" + appSupportPath + "'");
var nsError = $();
var contents =
ObjC.deepUnwrap(
$.NSFileManager.defaultManager.contentsOfDirectoryAtPathError(
$(appSupportPath + "/").stringByStandardizingPath, nsError)
);
if (!contents)
throw Error($(nsError.localizedDescription).js);
console.log("Contents of '" + appSupportPath + "':\n" + contents.join("\n"));
return "OK";
}
if (inDesignMode) {
return execute();
} else {
try {
return execute();
} catch (e) {
return "Error: " + e.message;
}
}
})(true);
Here’s what it shows:
Fully-enclosed script (surrounded by parens).
I usually code bottom-up, so the first lines executed are at the end. Sort-of.
The “if” and “try/catch” at the bottom is how I code things:
When running from Atom, I pass “true” in the last line, and when running in a KM action, I pass “false”, so I can test the variable “inDesignMode” to know which environment I’m running in.
My code makes sure that, when running not-inDesignMode, the script always returns “OK” if there are no errors, and always returns something starting with “Error:” if there are errors. Makes it easy to check the results.
When running inDesignMode, the errors show line numbers. They don’t show line numbers otherwise.
That‘s an excellent example, with many important basic maneuvers demonstrated! Many thanks. (Having this example somewhere very obvious would save a great deal of mucking around for anyone approaching JXA for the first time, especially people who are intimidated by the idea.
It would be nice if there were a category for example scripts — not scripts that do interesting or elaborate things, but scripts that are designed to demonstrate how to do various things in the various scripting languages. Yes I know that the JXA Cookbook cited in the next paragraph has some of this for JXA, but I don't know where to find such things for the other languages. I just do a lot of Googling, and collect good starting points. (See my Website Popups Using Automator, also known as Open Standalone Web Pages — Great for References.)
I've got my trivial alert script untangled. The problem is that there is no alert! (See User Interactions · dtinth/JXA-Cookbook Wiki for information on programming dialogues in JXA.) Here‘s what my successful script looks like now:
var app = Application.currentApplication();
app.includeStandardAdditions = true
app.displayAlert("atom.js");
I still don’t understand who is running the script (context).
I also don‘t understand how Atom knows to run this as JXA and not JavaScript or node.js. I did do the Edit | Select Grammar menu command — do you think that’s enough for Atom’s script package to know what to do?
I'm working on getting a new website running, and one of the things I will be doing is what you're asking for. I just keep getting sidetracked, but it will happen.
I still don’t understand who is running the script (context).
In Atom, go to Settings, then select Packages:
Put your cursor over "language-javascript-jxa", and click. It takes you to the support page for the package. And while there's only limited information there, you will discover this tidbit:
I was just thinking. One thing my JXA example script didn't make clear:
As written, it returns either "OK" or "Error:". But really, all that's required is "Error:". So you can actually return something meaningful when the result isn't an error.
Example:
The JXA script runs and returns the result in 'ScriptResult'.
If ScriptResult starts with "Error:", then an error occurred.
Otherwise, ScriptResult contains whatever you returned from the script. "OK" isn't very useful, but obviously you could return anything.
You can of course use something different than "Error:" to report an error, but I can't think of many situations where a non-error response from a script would start with "Error:", so this works.
Hope that helps.
Feel free to hit me up with questions, if you've got them. Either on the forum or via PM.
When you open a .js file or save a new file as .js how does it know to use JXA syntax and execution? Do you have to set that manually for each file as you are using it?
I do not have .js files associated with JXA. I have .scpt files associated with JXA, which I think is the default, but I might be wrong.
I could never figure out how to get .js files to be associated with JXA. I’m sure there’s a way, and if you figure it out, let me know.
As an aside, because I’m not using .js files for JXA, in order to get linter to work with .scpt files, I have to switch the grammar to JS when I want to use linter. Then I switch it back. I have some KM macros for this.
(It writes out text files with an .scpt extension – Script Editor often seems puzzled by them – reading but declining to resave/rewrite them, and is less puzzled or unprepared if they come back in with an .applescript extension)
Uh, this stopped working. Changing .currentApplication() to ("System Events") got it working again, but that it didn't work anymore is very disturbing.
The code above is working fine here – you may have to give me more context.
Note that if you don't enclose it in a module wrapper (as below), there can be collisions arising from pollution of the global namespace, including by successive runs of your own script.