“That way, I'm guessing I'd make use of the AE codes in the sdef and not the <cocoa> element KVC-compliant key mappings, and use those with the Carbon framework?”
I think you’re getting confused by the KVC data found in .sdef files. That data is not provided for clients’ use; it’s purely for use by the CocoaScripting framework upon which Cocoa-based apps implement their AE support. See `man 5 sdef` if you’ve not already done so.
As to navigating an app’s object graph, run-time introspection is poor/non-existent. CS-based apps have a standard `properties` property, but this only tells you about attributes and one-to-one relationships; it doesn’t tell you what one-to-many relationships (elements) exist. Nor is it a standard feature in older non-CS based apps (e.g. most MS, Adobe apps). You have to resort to reading the app’s aete/sdef; however, even that is troublesome, e.g. SDEF does not distinguish between attributes of type `text` (really, typeUnicodeText) and one-to-one relationships of type `text` (really cText), so you’ve no idea if a given property is one or other except to try querying elements (e.g. `every character of PROPERTY`) and see if the event succeeds or fails. Human users, of course, learn an app’s object model and recognize which is which, e.g. `name of front document of app "TextEdit"` vs `text of front document of app "TextEdit"`; an automated crawler will not, so will have to trial-and-error extensively.
And remember, AppleScript does not use any of that “type” information itself, so there are zero guarantees that information is accurate. e.g. Properties that can return, say, a string or `missing value` constant may declare their type as `text`, so even if you do a `get` there is no guarantee the result is a String. If you try to enforce that type (as SB does), you won’t get the right result. And that’s even before we consider implementation bugs in CS and/or apps, e.g. try `tell app "TextEdit" to get path of front document` and see what happens when the front document is newly created and hasn’t been saved yet. This is why SwiftAutomation leaves casting entirely to the client code, e.g. `PROPERTY.get() as String?`; it expects the code’s author knows that property returns either String or `missing value`, regardless of what the app’s dictionary may claim, so puts them in control. Works great, and takes advantage of the Apple Event Manager’s ability to coerce between various types so if you say `[String]` and the returned data is 1.0 then you’ll still get `["1.0"]`, but it’s not something you can automate as SDEF data’s not reliable enough.
Another example: `tell application "Finder" to get entire contents of desktop`, where the dictionary defines the `entire contents` property as type `specifier` (typeObjectSpecifier). Run that command and it returns a list of specifiers. Yet you can also write `tell application "Finder" to get name of every file of entire contents of desktop`, so it’s clear the property’s type is not a list. As with `text of front document of app "TextEdit"`, or `text of every document of app "TextEdit"`, what you get it partly dependent on the query you ask, and partly dependent on what the app anticipates is the most helpful result for you. (Unfortunately, while AE IPC has the facility to do content negotiation—see keyAERequestedType—it is poorly specced, underpowered, and rarely supported by applications.)
..
Again, if you’re trying to extract all data from each running app, you are going to be crushed at how unspeakably slow it all is, even if you do apply each `get` operation to all elements at once. I just did a job for a customer, automating a task in Adobe Illustrator, which I prototyped in Python3+appscript because AppleScript is just a PITA. That script only sent a few thousand AEs; took half an hour to run!!! I dunno exactly what it was tickling wrong (a couple minutes is more typical performance), but even on a good day AEOM queries are hella expensive and any form of IPC is inevitably magnitudes slower than in-process messaging. (The production version, written for Illustrator’s own in-process JS engine: 10secs.)
That’s why, in practice, we only query/manipulate the remote data we need. Pulling mass data over the wire is totally impractical performance-wise; plus there’s no transactional guarantees so even while you’re doing it the remote state may be simultaneously changing.
Apple event IPC may have its virtues—e.g. I’ve long argued its query-driven model could be a great match for Siri’s query-builder (especially if the AEOM spec was tightened up)—but when you get down to details it is painfully rough to deal with.
There’s two decades’ hard experience encoded in SwiftAutomation, and even then it’s not perfect, but it’s maybe worth a skim of the code just to get some appreciation of how and why it works the way it does. Because every other approach (gensuitemodule, JavaScriptOSA, aeve, RubyOSA, and of course ScriptingBridge) falls apart when real-world *AppleScriptable* apps stomp all over their assumptions.
Oh, and for general insight into Apple event IPC and how and why it works the way it does (and why it was left so awkward and unpolished), read this paper by one of its original designers:
www.cs.utexas.edu/~wcook/Drafts/2006/ashopl.pdf
You’ll learn more from that than you ever will from Apple’s own public developer docs, which are riddled with omissions and lies, it pains me to say.
Not trying to deter you, mind (must be a pretty good idea to make you so determined to pursue it!); just letting you know what a world of hurt you are in for! 😉