I made a library a while ago that dealt with this sort of thing, so I dug out a couple of handlers from it and checked it still works (in High Sierra). Despite my undying protestations against using Finder for anything AppleScript related except telling it to quit, I actually elected to use it for this task because it can enumerate a folder structure recursively with entire contents (if one knows how to use it optimally—I wrote a post about this a while ago outlining the principles of this), and because it allows one to enumerate scriptable applications that need not be running processes: every application file class object in Finder has the has scripting terminology property too.
On my clunky machine, the ScriptableApplications handler enumerates all scriptable applications within my /Applications directory in zero seconds, and does the same for /System/Library/CoreServices folder. These are the only two I’ve used it on, as they’re the only two that contain applications of any value to the user. If you want it to enumerate the entire hard drive, then you deserve what ensues (just don’t).
The ScriptingDictionary handler accepts a bundle identifier for the scriptable application for which you want to retrieve its .sdef file to open in Script Editor. There’s no error handling incorporated into this, so it’s not idiot-proof. If you pass it an application name, or a bundle identifier for an application that isn’t scriptable, it will throw an error. Like a lot of things, failure is the worst case scenario when calculating efficiency of an algorithm, as it only knows it has failed after checking every possibility. But if you pass it an option it can succeed with, it’ll do so reasonably quickly (about a second, maybe two). It only searches for .sdef files currently, so it will actually fail trying to get Script Editor’s dictionary file.
property directory : path to applications folder
use Finder : application id "com.apple.Finder"
property folder : a reference to folder (a reference to directory)
property contents : a reference to (my folder)'s entire contents
property list : missing value
on ScriptableApplications at path
local path
set my directory to the path as POSIX file
set my list to a reference to application files in its contents
script
property parent : my list
property id : my id
property key : my has scripting terminology
end script
tell the result
repeat with A in (a reference to id)
set [[x], key] to key's [it, rest]
if not x then set A's contents to false
end repeat
return id's text
end tell
end ScriptableApplications
on ScriptingDictionary for bundleid
local bundleid
set my directory to folder "Contents:Resources:" in ¬
application file id bundleid as alias
set my list to a reference to files in its contents
set my text item delimiters to linefeed
script
property parent : my list
property name : my name
property key : my name extension as text
end script
tell the result
set my text item delimiters to "sdef"
set i to the number of paragraphs in the key's first text item
set f to item i of the name
if f does not end with ".sdef" then return false
return file f in the folder directory as alias
end tell
end ScriptingDictionary
return ScriptableApplications at "/Applications"
tell application id "com.apple.ScriptEditor2" to open my (ScriptingDictionary for "com.apple.Reminders")
Whether this will work or not in Catalina is not something I’ll be in a rush to attend to, as I don’t use Catalina except for development, and I use Swift to do this job now. Although, I also just found this handler I wrote in AppleScriptObjC but never really used it:
to readSDEF for id
local id
(NSString's stringWithContentsOfFile:(firstObject() in ((NSBundle's ¬
bundleWithIdentifier:id)'s pathsForResourcesOfType:("sdef") ¬
inDrectory:(missing value)))) as text
end readSDEF
You’d need to add suitable headers to import Foundation and declare/define the two classes, but that can obviously replace the vanilla handler above very easily.
Model: MacBook 12" 2016
AppleScript: 2.7
Operating System: macOS 10.13