How to use JavaScript in a smart rule (finally)

No need for language wars. When is comes to languages just pick the best available tool for the job. Perl was made for this job but isn’t (directly) available.

The only reason Javascript is coming up here as a preference over Applescript is that it may be available natively, has infinitely better native support for the task at hand (uh, hello regex, arrays, etc.) and has an extremely large base of well-documented support.

1 Like

:slight_smile: Yeah, have to agree with ya there. Javascript is terse and its use of { }'s is overly zealous and irritating; not my personal preference just a better available tool for the job and, whether we like it or not, has a massive base of support load of examples for non-programmers and developers alike to choose from.

Personally I’d pitch for native Ruby support to expose many more people with little programming experience for readability and ease of entry but that’s not a (directly) available option.

One might question the assertion that

many, many Mac users prefer AppleScript.

I have a feeling that is because it was the only option natively available. A quick search led me to this quote in The unlikely persistence of AppleScript MacWorld article which sums it up better than I ever could.

What makes it so surprising that AppleScript survived … is that it was never loved by anyone. It was a fine theory and noble experiment, but it turns out that an English-like programming language didn’t really enable a large number of users to become programmers. And conversely, AppleScript’s English-like syntax often made (and to this day continues to make) things more difficult and confusing for scripters, not less.

However, I’m sure it may have some fans.

In my case however, AppleScript has prevented me from fully embracing DevonThink for 5 years now. Once or twice a year, I revisit DevonThink only to get frustrated by the self flagellation of AppleScript when running into a limitation. I’m certain that I’m not alone on this.

AppleScript is a barrier to entry for everyday people and seasoned software engineers alike; remove the barrier and more people will get excited instead of stifled.

No need for language wars, more tools in the toolbox is never a bad thing!

2 Likes

Now that hopefully everybody has explained why they (don’t) like this or that language, maybe we could

  • either get back to the problem at hand (if there is one)
  • or just leave it at that

I try my luck with the first possibility now. Here’s what I found out about when/if an external JavaScript script does (not) work in a smart rule. Take a very simple example:

function performsmartrule(recs) {
  let app = Application("DEVONthink 3");
   recs.forEach(r => {
    app.logMessage(r.name());
  } )
}

This code should only write the names of the selected records to DT’s log window. Which in fact it does not, it writes nothing. At least not for me. However (fasten your seat belts, please), if I add this snippet to the end of it

(() => {
  let app = Application("DEVONthink 3");
  performsmartrule(app.selectedRecords());
})();

the code does what it’s supposed to do in DT (and of course in Script Editor). See explanation at the end of the post. I must apologize that I didn’t mention that piece of code before, but it seemed irrelevant to me and only necessary to have the script run in Script Editor.

Some more experimentation showed that

  • the name of the function must be performsmartrule: changing it to foo in the definition and the call results in the script not doing anything.
  • the name of the function in the call (i.e. at the end of the script) must also be performsmartrule.

This seems to indicate that on the one hand, performsmartrule is called by DT. On the other hand, it seems also to indicate that the self-executing function added in step 2 above is also run.
If there’s somebody out there who can explain that … please, shed some light on this.

Explanation: The code added in the 2nd step above is a “self-executing anonymous function”. Anonymous, because it has no name. It also has no parameters, as indicated by the first pair of empty parenthesis. It’s self-executing because of the last pair of empty parenthesis following the function definition.

3 Likes

No. I like AppleScript.

2 Likes

Pete, shhhhh now! :smiley:

(:+1: @chrillek thanks for your perseverance & explanations)

2 Likes

The approach taken by Hook Productivity would work well here, and would be more consistent with Apple policy, the functioning of all other applications on macOS, and proper respect for the time and equanimity of DEVONthink customers.

(protecting customers from the rabbit holes, tar-pits, and XKCD-joke vultures that now cluster and circle so tightly and so disablingly around the use of regular expressions and JavaScript generally in DEVONthink Smart Actions)

In Hook scripts:

  1. Any script that begins with the two characters // is passed to osascript -l JavaScript
  2. any other script is passed to osascript -l AppleScript

(where the -l switch selects between available OSA components)

In Terminal.app, see:

  • man osalang
  • man osascript
  • man osacompile

Yes, there is still a problem that am still banging my head against trying to solve.

Running the very simple example produces:

  • on performSmartRule (Error: Error: No error.)

Adding the code in the 2nd step:

  • document name
  • on performSmartRule (Error: Error: No error.)

Now that is definitely progress!

Also tried changing r.name() to r.plainText() and woot! We are cooking with gas!

You are the (insert your preferred gender identity noun here)! Once I ice my noggin’ can get back to work after this 3 day distraction. There’s no way I would have stumbled on that missing bit without your help.

1 Like

Weird. Internally DEVONthink uses indeed performSmartRule, not performsmartrule.

An automatic derivation, I think, from the name used in the .sdef file:

This would be also weird as performSmartRule is just the name of a function whereas perform smart rule is a command of DEVONthink. Well, the joys of the AppleScript-JavaScript bridge probably :grinning:

1 Like

There’s a bridge to ObjC, but there’s no bridge between AppleScript and JavaScript :slight_smile:

(Just peer System/Library/Components components mapping scripts in particular languages directly to the OSA framework)

(This passage in the Automation section of the Help file is actually misleading:

The JavaScript component does not, in any way, or at any stage whatsoever, make any use at all of the AppleScript component. It interacts directly with the OSA framework.