Debugging an AppleScript Handler in VBA

Debugging an AppleScript Handler in VBA

Script Debugger vs Apple’s Script Editor

AppleScript is designed to help automate simple tasks that you need to do often, without the need for learning a high level language like Objective C. While it’s been billed as closer to “natural language,” I find it a bit quirky, but I’m slowly getting used to it. Apple’s Script Editor, however, leaves something to be desired. Debugging scripts in Script Editor forces the developer to use lots of log messages which can only be comfortably reviewed after the script is complete. Anoher alternative is Display Dialog, which is widely discouraged for debugging.

Enter the Script Debugger. I’ve used lots of interactive symbolic debuggers in my time and Script Debugger replicates the best features of most of them, particularly single-stepping and variable examination and editing. When I met Script Debugger, I gave a huge sigh of relief. At last I was able to see what was going on as the script progressed. When it failed, I could identify the problem with little guesswork. I can watch what happens one step at a time and can make quick fixes and then re-run.

Overview

I initially started to write a simple how-to for debugging a VBA-to-Applescript connection. It turned out to be more complicated than I thought, due to differences in calling sequences between Excel versions. So this is a longer, but more complete coverage of the concept.

This article addresses How To:

  • Debug your AppleScript scripts when called from Microsoft Excel VBA (Visual Basic for Applications)
  • Pass parameters from VBA to AppleScript handlers
  • Separate code for two different versions of Excel
  • Produce code that can handle both versions of Excel

Quick Links to Topics in this article

Debugging AppleScript

Normally, to use Script Debugger, you select or double-click an AppleScript file and it opens up, ready to go to work. You can debug most AppleScripts this way just fine. I call this Direct debugging.

Sometimes invoking a script, already debugged using the direct method, from another application like VBA, can cause unexpected problems. That’s when we need what I term Indirect debugging.

Both are described in detail in the following sections.

Direct debugging

For most scripts, all you have to do is turn on the debugger and single-step through, or set breakpoint(s) and run till they pause the execution. Easy as pie.

Debugging a handler (Apple’s term for what the rest of us might call a subroutine) is comfortably handled by Script Debugger. Here’s an example of a handler that splits a string based on a delimiter.

# main line 
set SplitArray to split("String 1|String 2|String 3", "|")

# the handler
# Ref: https://erikslab.com/2007/08/31/applescript-how-to-split-a-string/
on split(theString, theDelimiter)
	local oldDelimiters, theArray – allows local variables to be seen by the debugger
	set oldDelimiters to AppleScript's text item delimiters -- save delimiters to restore on completion
	
	set AppleScript's text item delimiters to theDelimiter -- set delimiters to delimiter to be used
	set theArray to every text item of theString -- create the array
	
	set AppleScript's text item delimiters to oldDelimiters -- restore the original setting
	return theArray -- return the result
end split

A handler is not run unless invoked by mainline. When this is executed, the mainline code runs and calls the handler, just like other languages call subroutines. While debugging in Script Debugger this way, logged messages are visible in the log pane, and other valuable information can be displayed in other panes.

A handler can also be called by an external program such as VBA.

Indirect Debugging from VBA

VBA is a macro programming language underlying the apps in Microsoft Office: Excel, Word, Access, Outlook and others. It works in Windows remarkably well and I have used it since the 90’s for more than one client. Under MacOS, it appears to be a bit handicapped. For example, the Mac’s long file names cause errors, and it can’t do timed dialog boxes. AppleScript to the rescue; it can do many of the things that MS left out of the Mac version of Office, although at the expense of a bit slower execution time.

But herein lies a problem. You can debug your individual routines/handlers using the direct method but adding VBA to the mix introduces a new level of complexity. When you call an already debugged AppleScript script from VBA, you are likely to see this:

You can’t tell from looking at that what the problem is. Just a vague error message that something unspecified went wrong. (One of my complaints about VBA has always been some of the generic non-specific error messages, but that’s another story.)

So how can you debug a handler invoked from VBA? While you might have logging as part of the script, that log disappears once the script completes and you don’t get to see it. Display Dialogs are poor substitutes.

The answer: use Script Debugger to call itself. It took me a while for that to sink in. It turns out that the Script Debugger developers included an incredible list of scriptable features in Script Debugger. I won’t go into detail, but go to Menu > Window > Dictionary and pick the little red ladybug. You’ll see quite an array of properties and methods that should give you lots of ideas.

I’m going to show you a set of simple VBA to Script Debugger scripts that should give you enough to get started with your own. First, though, I have to tell you: Because of security restructuring, it is different for Excel 2011 and Excel 2016/2019, so we need separate solutions for each. For more information on the reasons and the methods, visit Ron de Bruin’s excellent web page at https://www.rondebruin.nl/mac/applescripttask.htm.
In fact his whole site is full of good stuff, much of it focused on VBA for Mac.

Excel 2011

Method 1 – VBA-Generated AppleScript

This is for simple scripts that are not hard to debug visually. Write an Excel VBA procedure that creates an AppleScript script and pass it to the MacScript statement to be executed. For example, the following creates a dialog box with a timeout, so if the user doesn’t respond within a specified time frame, the default button is used and the box closes.

For this version, we will need only one piece of code:

  • VBA code to create the AppleScript handler being debugged

VBA Code

Create a new workbook, open the VB editor and insert a new module.

Sub Process_Copmlete()
    Dim myScript As String
    Dim Response As String
    
    myScript = "set ProcNameMsg to ""The Purge process is complete""" & vbCr
    myScript = myScript & "Beep" & vbCr
    myScript = myScript & "set {gave up:gaveUp} to display alert ProcNameMsg " & _
                "buttons {""Stop"", ""Continue""} default button ""Continue"" giving up after 5" & vbCr
    myScript = myScript & "If gaveUp Then" & vbCr
    myScript = myScript & "    set Response to ""Continue""" & vbCr
    myScript = myScript & "Else" & vbCr
    myScript = myScript & "    set Response to button returned of result"
    myScript = myScript & "End If"

    Response = MacScript(myScript)   ' invoke Applescript
End Sub  ' Process_Copmlete

Copy this procedure to VBA and run it. Surprise! You get the dreaded Run-time error 5. With no information to go on, you’ll have to scan the code in VBA. Clearly the VBA code obfuscates the AppleScript code. Here’s the answer: set a VBA breakpoint at the MacScript line and run it again. When it pauses, go to the Immediate Window and type Print myScript. What you see is:

set ProcNameMsg to "The Purge process is complete"
beep
set {gave up:gaveUp} to display alert ProcNameMsg buttons {"Stop", "Continue"} default button "Continue" giving up after 5
if gaveUp Then
    set Response to "Continue"
else
    set Response to button returned of resultEnd If

This is exactly what the AppleScript process sees. It looks okay all the way to the bottom line. Oops, the problem is resultEnd. VBA wasn’t told to put a carriage return at the end of the previous line. Modify that line as follows:

    myScript = myScript & "Else" & vbCr
    myScript = myScript & "    set Response to button returned of result" & vbCr
    myScript = myScript & "End If"

Now hit the Reset button and try running it again. This time you get the intended dialog box:

Image2

This has demonstrated the easiest way to debug your VBA to AppleScript: Print the script and scan for errors. You can test that the buttons work correctly and that if you do nothing, the box closes itself after 5 seconds.

Next, if you still can’t see any error(s) in the AppleScript, you can copy the results from Debug Print and paste it into Script Debugger and see if it compiles. If not, the error message will help you determine what the problem is. If it compiles, try stepping through it till it fails, then identify and fix that problem.

The worst case occurs when the same code fails when run from VBA and works fine when run from Script Debugger. That is a nightmare I have encountered occasionally and, to be honest, I don’t know why it happens; perhaps some quirk in the communications between the two. Fortunately, it doesn’t happen often. If it does, then you may have to design a workaround within AppleScript, but that is well beyond the scope of this article. I’ve included a list of the most common problems I’ve encountered, further along.

So, Method 1 has shown you how to copy the code back and forth between VBA and Script Debugger. If you get your AppleScript code working in Script Debugger, then copy it to VBA and form it into a string for MacScript. If it doesn’t work from VBA, copy it to Script Debugger and try to run it.

Method 2 – External AppleScript Script

When your AppleScript code gets complex and lengthy, examining the VBA code that generates it can get pretty dicey. This is where we utilize Script Debugger’s ability to invoke itself. To summarize the process: VBA code generates an AppleScript that invokes Script Debugger, which in turn invokes itself to debug the desired AppleScript script.

For this version, we will need two pieces of code:

  • VBA code to create the AppleScript debug handler which will call the handler to be tested/debugged
  • The actual AppleScript handler being debugged

VBA Code

Option Explicit

Sub Test_Handler()
' Debugging AppleScript from VBA

    Dim myScript As String

    myScript = "tell application ""Script Debugger""" & vbCr
    myScript = myScript & "  tell document ""Testing.scpt""" & vbCr
    myScript = myScript & "    Debug_Handler(""Counting Tags"", ""Keep on Testing!"", ""5"")" & vbCr
    myScript = myScript & "  end tell" & vbCr
    myScript = myScript & "end tell" & vbCr

    MacScript myScript
End Sub  ‘ Test_Handler

Create a new workbook, open the VB editor and insert a new module. Copy this code into the new module. Save it as any name you want. I used the descriptive title of Test.xlsm. This represents the VBA script you need to invoke the AppleScript task. Be sure you don’t have two copies of the first line (Option Explicit).

AppleScript Code

on Debug_Handler(P1, P2, P3)
	local Parms
	set Parms to P1 & return    -- set breakpoint here
	set Parms to Parms & P2 & return
	set Parms to Parms & P3 & return
	display dialog "This is a message from the handler" & return & ¬
		Parms buttons {"OK"} default button "OK"
end Debug_Handler

Open Script Debugger, create a new script and paste this code into it. set a breakpoint on the first set Params line then save it, in debug mode, as Testing.scpt, which you’ll notice is the name of the document in the VBA script. Also notice that the name of the handler (Debug_Handler) is the same as the name inside the tell document block above. This represents the script you want to debug.

Image3

Now, to debug this, make sure that Testing.scpt is open in Script Debugger. If you closed it, reopen it and make sure it’s in debug mode. Open your workbook to the VB editor and run the sub Test_Handler. The Script Debugger window should activate, with the script paused at the line with the breakpoint. At this point you can examine variables, log messages, and single-step through the rest of the script. Since this one is so simple, there isn’t much to see besides Parms. The dialog box pops up and shows the message and parameters.

After debugging is complete , you have two choices.

  • Implement the debugged AppleScript code using inline code to pass to MacScript, similar to what we did in an earlier VBA procedure. It might look like:

    Sub Test_Handler2()
        Dim myScript As String
    
        myScript = "set Parms to ""Counting Tags"" & return" & vbCr
        myScript = myScript & "set Parms to Parms & ""Keep on Testing!"" & return" & vbCr
        myScript = myScript & "set Parms to Parms & ""5"" & return" & vbCr
        myScript = myScript & "display dialog ""This is a message from the handler"" & return & Parms" & " buttons {""OK""} default button ""OK""" & vbCr
        
        MacScript myScript
    
    End Sub  ' Test_Handler2
    

    A couple of things to note: you don’t include the handler’s on (a “Begin” construct) and end. You don’t pass parameters; you just include them in the code. And you may still run into the dreaded Run-time error ‘5’, the elimination of which was the whole point of this exercise. That’s most likely because you had to change the code to plug it into MacScript.

  • Invoke the unmodified debugged handler script. This is desirable, since you don’t have to touch the AppleScript code that you know works. But it does involve a bit more twiddling with VBA. Here’s an example:

    Sub Call_Handler()
        
        ' Script path under user's home folder - change these to match your folder structure
        Const YourUserName As String = "Chuck"   ' MacOS user name
        Const HandlerScriptPath As String = "/Users/" & YourUserName & _
                        "/Desktop/Development/Debugging VBA and AppleScript/2011/"
        
        Const HandlerScriptName As String = "Testing.scpt"  ' script file name
        Const HandlerName As String = "Debug_Handler"       ' name of the handler
        
        Const P1 As String = "Counting Tags"
        Const P2 As String = "Keep on Testing!"
        Const P3 As String = "5"
            
        Dim Response As String
        Dim InvokeHandlerScript As String
        
        InvokeHandlerScript = "Set HandlerScript to load script (""" & HandlerScriptPath & _
                        HandlerScriptName & """)" & vbCr
        InvokeHandlerScript = InvokeHandlerScript + "HandlerScript's " & HandlerName & _
                        "(""" & P1 & """, """ & P2 & """, """ & P3 & """)" & vbCr
    
        Response = MacScript(InvokeHandlerScript)   ' Call the AppleScript routine from Excel 2011
    
    End Sub  ' Call_Handler
    

    Copy this VBA code into a new module and run it. It should bring up the dialog box you already saw in the debugging step.

    Some things to mention about this code:

    • The VBA procedure name can be anything you want. It is not significant to the process.

    • Define your user name and the full path to the script. It is widely recommended that you store all your AppleScripts in a single location for convenience and consistency.

    • If you change script file name and/or handler name, be sure to change them here, or VBA won’t find them and you’ll get the dreaded error 5 message.

    • You can pass any number of parameters to the VBA routine to pass along to the AppleScript handler.

    • If you print the InvokeHandlerScript variable, you’ll see:

      Set HandlerScript to load script ("/Users/Chuck/Desktop/Development/Debugging VBA and AppleScript/2011/Testing.scpt")
      HandlerScript's Debug_Handler("Counting Tags", "Keep on Testing!", "5")
      

      This is an AppleScript method of calling a handler in another script file. I’m going to describe it a little more detail because it’s employed in another script further on.

      The first line defines a variable named HandlerScript, to hold the full path name of the handler script.

      The second line invokes the handler from that script file and passes the defined parameters to it. You can use it in your own scripts if, for example, you have a number of handlers dedicated to different purposes and have gathered them by function into separate script files. So a routine in one script file can call a handler in another script file, just as if they were in the same file.

Now that you see how it works, you should be able to use this method on your own scripts.

Excel 2016/2019

For security reasons, this version of Excel doesn’t allow you to create scripts on the fly and execute them from VBA. It requires that the handler, which will do the work, must already exist in a shared library folder dedicated to Excel. You must then invoke that existing script from VBA. If it seems convoluted, you’re right. Go read Ron de Bruin’s explanation.

The process for this version is nearly identical to Method 2 above. The three differences are:

  • Script files invoked by Excel VBA must be stored in Excel’s shared library folder.
  • MacScript has been replaced by AppleScriptTask
  • AppleScriptTask permits only one parameter to be passed to the handler.

For this version, we will need three pieces of code:

  • VBA code to call the AppleScript debug handler
  • The AppleScript debug handler which will call the handler to be tested/debugged
  • The actual AppleScript handler being debugged

VBA Code

This code sets up the call to a AppleScript handler, which will in turn call Script Debugger to allow interactive debugging of the handler under development.

Option Explicit

Sub Test_Handler_2016()
    Const HandlerScriptName As String = "Testing Handler2016.scpt" ' name of the script file
    Const HandlerName As String = "Debug_Handler2016"        ' name of the handler 

    Dim Response As String
    Dim ParameterList As String

    ParameterList = "Counting Tags|Keep on Testing!|5"   ' | is the parm delimiter
    Response = AppleScriptTask(HandlerScriptName, HandlerName, ParameterList)
End Sub  ' Test_Handler_2016

Copy this to a new module in the workbook you’ve been using.

Some things to mention about this code:

  • Of course, you must be running Excel 2016 or 2019 for this to work, since MacScript was deprecated after version 2011.
  • Likewise, AppleScriptTask will not run under 2011.
  • Like an earlier procedure, the VBA procedure name can be anything you desire. It is not significant to the process.
  • You can only pass one parameter to the handler. This could be a significant barrier to serious development, except that you can concatenate multiple parameters in a single string, separated by a delimiter. The handler must then split them into their separate pieces (remember the Split handler shown earlier?). I generally use the gravé (the backwards apostrophe also known as the “back-tick,” above the tab key on the main keyboard), because it never otherwise appears in my scripts.
  • Note: I’m using the vertical bar in this document because it is more recognizable and easier to see. You are free to use whatever you prefer as long as it does not conflict with characters in your parameters.
  • If you change script file name and/or handler name, be sure to change them here, or VBA won’t find them and you’ll get the dreaded error message.
  • You don’t have to provide a path to the script file – Excel assumes you have placed it in a specific folder dedicated to the purpose. For Excel, the path is
    /Users/YourUserName/Library/Application Scripts/com.microsoft.Excel/
    If the folder does not exist, you must create it – you can use mkdir for that. Be sure to spell it EXACTLY as shown – any difference in case or spelling will prevent Excel from finding it.

AppleScript Code (debug handler)

This code is strictly for debugging. It will not go into production.

on Debug_Handler2016(ParameterList)
	tell application "Script Debugger"
		tell document "Testing 2016.scpt"
			Debug_Handler2016(ParameterList)
		end tell
	end tell
end Debug_Handler2016

Create an AppleScript file and copy the above into it. Save it to the Excel shared library folder (identified above) with the name Testing Handler2016.scpt.

AppleScript Code (handler being debugged)

This code is what will, when debugging is complete, become the production routine, to be called by VBA, without the Testing Handler2016.scpt handler in between.

on Debug_Handler2016(ParameterList)
	local Parms, myArray
	set myArray to Split(ParameterList, "|")  -- set breakpoint here
	set Parms to item 1 of myArray & return
	set Parms to Parms & item 2 of myArray & return
	set Parms to Parms & item 3 of myArray & return
	display dialog "This is a message from the handler" & return & ¬
		Parms buttons {"OK"} default button "OK"
end Debug_Handler2016

on Split(theString, theDelimiter)
	local theArray
	set oldDelimiters to AppleScript's text item delimiters -- save default delimiters 
	
	set AppleScript's text item delimiters to theDelimiter -- note delimiter to be used
	set theArray to every text item of theString -- create the array
	
	set AppleScript's text item delimiters to oldDelimiters -- restore original delimiters
	return theArray -- return the result
end Split

Set the breakpoint at the set myArray line, turn debugging on, and save the file in the Excel shared library folder (identified above) with the name Testing 2016.scpt. Keep it open for the test. If it is not open, you can expect the dreaded Run-time 5 error. My experience has shown that it can crash Excel, so make sure the script is open in Script Debugger.

Run the VBA routine and watch Testing 2016.scpt pause at the line with the breakpoint. Single step through and watch the array and variables get established, and the result from the dialog box. You could fix any bugs you discovered and repeat until you were satisfied it was running correctly.

After debugging is complete, turn off debugging in the script file Testing 2016.scpt, save it as a compiled script, then close it. Return to the VBA code and change the name of the script file to Testing 2016.scpt. You can then run the VBA code again and the dialog box pops up without Script Debugger showing itself. You can delete or retain the script file Testing Handler2016.scpt.

That’s it. You have debugged the AppleScript file and VBA code at the same time.

Coding VBA for Both Versions

As mentioned earlier, the means of calling AppleScript for Excel VBA 2011 differs from that of 2016/2019. 2011 uses the MacScript call while 2016/2019 uses AppleScriptTask. This means that code designed for 2011 will not work in 2016/2019, and vice versa. In fact it won’t even compile - it will give an error message and refuse to execute.

If you are only writing for one version, then you can skip this section and use code for only the your version. Otherwise:

One solution is to maintain two code bases, one for each version. But there is an alternative: conditional compilation, which means that you use the same code for all bases, but build a wrapper around each version’s code that compiles only if that one is executing. The result is not necessarily prettier code, but it does simplify things quite a bit. It uses Excel’s internal constants to determine which version and compile/execute only the code designed for it. It can also distinguish between Windows and MacOS platforms.

Again, I refer to Ron de Bruin – I learned a lot from him. He showed me how to determine which platform (Window, MacOS, Linux) your code was operating under and which version of Excel was running. I am providing an example here and you should be able to use it for your own purposes. Assuming you have to produce code that will work under multiple conditions. If not, consider yourself lucky.

Now, like so much else in this area, there are two ways you can implement this:

  • Include the complete routines for both versions and put them inside wrappers for their version. This is best for small routines that are pretty simple and don’t have much in common. A simple example follows:

    #If Mac Then ‘ MacOS only code
        #If MAC_OFFICE_VERSION < 16 Then ' call this routine from Excel 2011
            Function test()
                Debug.Print "Test - for 2011"
            End Function
        #Else        ' Call this routine from Excel 2016 and 2019
            Function test()
                Debug.Print "Test - for 2016 and 2019"
            End Function
        #End If
    #Else  ‘ Windows only code
        ' Windows does not use appleScript, so this will never happen.
    #End If
    

    Note that the routines have the same name (“Test”). Without the #If - #End If wrappers, this would throw an error: “Ambiguous name detected: Test”, but conditional compilation keeps them from interfering with each other.

  • Consolidate the routines into a single routine and place the wrappers around segments dedicated to each version. This is best for large, complicated routines. What follows is a merged version of the routines for Excel 2011 and Excel 2016/2019:

    Sub Test_Handler()
        ' these would be passed parameters
        Const P1 As String = "Counting Tags"
        Const P2 As String = "Keep on Testing!"
        Const P3 As String = "5"
        
        Dim HandlerScriptName As String   ' script file name
        Dim HandlerName As String         ' name of the handler
        Dim Response As String
    
    #If Mac Then
        #If MAC_OFFICE_VERSION < 16 Then ' call this routine from Excel 2011
            Const YourUserName As String = "Chuck"   ' MacOS user name
            Const HandlerScriptPath As String = "/Users/" & YourUserName & _
                        "/Desktop/Development/Debugging VBA and AppleScript/2011/"
            Dim InvokeHandlerScript As String
            
            HandlerScriptName = "Testing.scpt"
            HandlerName = "Debug_Handler"
        
            InvokeHandlerScript = "Set HandlerScript to load script (""" & HandlerScriptPath & _
                        HandlerScriptName & """)" & vbCrLf
            InvokeHandlerScript = InvokeHandlerScript + "HandlerScript's " & HandlerName & _
                        "(""" & P1 & """, """ & P2 & """, """ & P3 & """)" & vbCrLf
    
            Response = MacScript(InvokeHandlerScript)   ' Call AppleScript routine from Excel 2011
    
        #Else        ' Call the AppleScript routine from Excel 2016 and 2019
            ' Script path under user's home folder - change these to match your folder path
            Dim ParameterList As String
    
            HandlerScriptName = "Testing 2016.scpt"
            HandlerName = "Debug_Handler2016"
    
            ParameterList = P1 & "|" & P2 & "|" & P3   ' | is the parm delimiter
            Response = AppleScriptTask(HandlerScriptName, HandlerName, ParameterList)
        #End If
    #End If
    
    End Sub  ' Test_Handler
    

Note a few things about this routine:

  • Code that is common to both versions can be kept outside the conditional compilation wrappers. That would include testing the Response variable if you chose.
  • They use different methods of parameter passing. One passes parameters separately and the other combines them to be separated by the handler. This of course implies that each uses their own handler. One could revise the MacScript parameter list to combine them as done with AppleScriptTask, and then they could use the same handler. You would also have to force MacScript to look in the Excel shared library folder as AppleScriptTask does, and make sure you copy the handler there.
  • If you try to place a breakpoint in the code for the other version, it will not be accepted, because the code does not get compiled. So don’t even try.

These are left as an exercise for the Very Dedicated. Have fun with it. There are lots more things you can do.

Causes of Run-Time Error 5

During your debugging, you’re likely to encounter many times the dreaded Run-Time Error 5. Working your way through that and other errors is going to take time and patience. But then, as a developer, you probably already know that. Here are some of the problems that caused me that error:

  • Wrong script file name or file missing. If you change the name one place, the process can’t find the file. Same if you have forgotten to place the file in the expected location. Just imagine, you’re looking through the phone directory for “Sarah Connor” and she’s moved.
  • Wrong handler name or handler is not in the file you specified. Just like the file name, if the handler name can’t be found, things will fail.
  • Wrong number of parameters. VBA has optional parameters, but AppleScript does not. The number of parameters must match. Good news: AppleScript converts all parameters to strings and deals with that at execution time, so parameter type is irrelevant.
  • AppleScript was saved in debug mode by Script Debugger. Re-open the script, take Script Debugger out of debug mode and save it back.
  • File path specification error: HFS instead of POSIX or vice versa: Study up on how to specify the path of a file or folder. It matters because 2011 does it differently than 2016/2019, and Finder does it differently than everybody else. Sorry.
  • Untrapped error in the script: Use the Try-Catch construct to allow you to trap errors and return problem status to the calling routine.

Recommended AppleScript Web Sites

Jerry Krinock
https://gist.github.com/jerrykrinock
This guy is amazing. He has developed an incredible number of things AppleScript can do for you.

Ron de Bruin
https://www.rondebruin.nl/index.htm
I’ve mentioned his site a couple times here. His tips for Mac are enlightening.

Alvin C – unforswearing
https://github.com/unforswearing/applescript
A substantial number of useful scripts, helpfully categorized. Also lists other AppleScript resources.

2 Likes