Problem With JXA ObjC Code in Shell Script in Plugin Action

OK, ready for a good laugh? As often happens, I disagree with @JMichaelTX, do it my own way, and end up agreeing with Jim.

This is another case of that, although the reason I ended up agreeing with Jim isn’t entirely because of his arguments, but because, in the long run, it solves a problem and performance is (possibly) better.

###First issue: Parameters with multiple lines, or quotes, etc.

Using the "$KMPARAM_Variable_Name" method, the script will fail if the parameter contains multiple lines, or embedded quotes, and possibly other special characters.

###Second issue: Performance

If I don’t use the "$KMPARAM_Variable_Name" method, then I don’t have to run it in a shell script. Instead, I can compile the JXA script (using Script Editor), and have the plugin run the compiled script directly.

NOTE: I haven’t measured the speed difference, but it seems reasonable that running a compiled script will execute faster than using a shell script containing uncompiled JavaScript. I could be wrong, but it doesn’t really matter, because the first issue is the most relevant.


So, here’s an example of how I’m coding it now:

 1 (function(inDesignMode) {
 2     'use strict';
 3     ObjC.import('stdlib');
 4 
 5     function getPluginParameter(name) {
 6         var envName = "KMPARAM_" + name.replace(/ /g, "_");
 7         var result;
 8 
 9         if (!inDesignMode) {
10             result = $.getenv(envName);
11             return result ? result.trim() : "";
12         }
13 
14         var designingParams = {
15             KMPARAM_Sort_Order: "newest first",
16             KMPARAM_Timestamp_Format: "date + time + duration"
17         };
18 
19         result = designingParams[envName];
20         if (result === undefined)
21             throw Error("Unknown Plugin Parameter Name '" + name + "' while in designing mode");
22         return result;
23     }
24 
25     function execute() {
26         var sortOrder = getPluginParameter("Sort Order");
27         var timestampFormat = getPluginParameter("Timestamp Format");
28 
29         return "Sort Order: '" + sortOrder + "'\nTimestamp Format: '" + timestampFormat + "'";
30     }
31 
32     if (inDesignMode) {
33         return execute();
34     } else {
35         try {
36             return execute();
37         } catch (e) {
38             return e.message;
39         }
40     }
41 })(true);

Click here for version without line numbers

###Point of Interest # 1:

Notice that I’m passing a parameter to the main function indicating whether I’m running in design mode or not. See lines 1 and 41. This allows me to change how the code operates when I’m testing it in Script Editor or Atom, compared to how it runs when the plugin executes it

###Point of Interest # 2:
The function “getPluginParameter”, lines 5-23.

I call this passing the plugin parameter name, as it is specified in the plugin’s plist file. The function converts it to the environment variable name. This is merely a design choice on my part, but it allows me to easily use the parameter name when throwing exceptions. I suppose this might add some execution time, but I doubt it’s measurable.

The function either returns the environment variable value or a hard-coded test value, depending on whether inDesignMode is true or not (see point # 1, above).

You may wonder why I coded lines 14-22 the way I did, instead of just using a switch statement. The reason is that, as you can see in lines 14-17, that the test values are easily identifiable, and color-coded to make it easy to pick out the values vs. the names.

1 Like