Need a Script for OO 5.2

Sadly, I have no scripting abilities, and need what I think is a fairly simple one: I have a long document in which every item has a Note. I’d like to add an empty line at the end of every note. Can anyone show me how to do this?

Much thanks …

There are various approaches – one might look a bit like this:

-- withAdditionalNoteText :: String -> OO Row -> OO Row
on withAdditionalNoteText(strText, oRow)
    using terms from application "OmniOutliner"
        set note of oRow to (note of oRow & strText)
        oRow
    end using terms from
end withAdditionalNoteText


-- TEST ------------------------------------------------------------------
on run
    set strExtraText to linefeed
    
    tell application "OmniOutliner"
        tell front document
            my map(|λ|(strExtraText) of my ¬
                curry(withAdditionalNoteText), rows)
        end tell
    end tell
end run


-- GENERIC ---------------------------------------------------------------

-- curry :: ((a, b) -> c) -> a -> b -> c
on curry(f)
    script
        on |λ|(a)
            script
                on |λ|(b)
                    |λ|(a, b) of mReturn(f)
                end |λ|
            end script
        end |λ|
    end script
end curry

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn
1 Like

Another would be a JavaScript for Automation script which runs an omniJS (‘Omni Automation’) script inside OmniOutliner’s own JSContext

You can run this from Script Editor with the language tab at top left set to JavaScript, or install and launch it from the same contexts as AppleScripts:

(() => {
    'use strict';

    // OMNIJS CODE -----------------------------------------------------------
        
    const JSContext_OO = () =>
        rootItem.descendants.map(
            x => x.note = x.note + '\n'
        );

    // JXA CODE --------------------------------------------------------------

    return Application('OmniOutliner')
        .evaluateJavascript(
            '(' + JSContext_OO + ')()'
        );
})();

That worked great. Thank you so much!

1 Like

Here’s an Omni Automation script for adding a blank line to every note that is not empty:

rootItem.apply(function(item){
	if (item.note != ''){
		item.note = item.note + "\n"
	}
})

Hi Sal, I wonder if it might not help to prepare a basic link or footnote to regularly accompany omniJS snippets, whether for OmniOutliner, OmniGraffle, or in due course other apps ?

Many users:

  • still seem a little unfamiliar with the notion of Omni-app scripts in any kind of JavaScript,
  • are even less clear about and the notion that might actually be two different JS APIs for one Omni application

and I suspect that most users (including to some extent myself :-)

  • have really no idea at all about the best way (or perhaps any way) of conveniently running what you refer to above as an “Omni Automation” script, and which I can see, by inspection, refers to an omniJS script.

I do appreciate that there might be some hope that use of a term like ‘an Omni Automation script’ would lead users to a search engine, and thence to your own site of that name, but the real traffic would probably be increased by at least a link …

(The status of your site could, I think be another source of confusion. The naming suggests a formal link with OmniGroup, but Omni support staff seem to play down any such link if users come to them for clarification about material or technical issues encountered on your site)

The real problem though, in these early days of the excellent omniJS initiative (scripting OmniGroup apps with new and much faster APIs which run in JavaScript Contexts embedded in the OmniGroup apps themselves, rather than in JXA) is that:

  1. At this early stage it’s still fiddlier and less convenient to run omniJS scripts than AS/JXA scripts
  2. It’s much harder to test and debug them, because outside the special console, they still provide no mechanism for returning a value to the caller
  3. For the same reason (no return values), they are not yet at all well-adapted to the main use case of OmniOutliner scripting, which is data format conversion
  4. Assigning them, once made, to convenient buttons or keystrokes It’s still fiddlier and more obscured, and much less well understood than in the case of the older and slower AppleScript

To summarise

  1. The splitting of Omni (indeed Apple platform(s)) scripting into two idioms (AppleScript and JavaScript for Automation) is still not widely or fully digested.
  2. The further splitting of JavaScript scripting for for Omni apps into two APIs and two evaluation contexts is even less widely known or understood
  3. Splitting even the nomenclature of the latest bifurcation into omniJS vs “Omni Automation” (which sounds as if it could mean AppleScript, JavaScript for Automation, or omniJS, seems a bit unlikely to help with points one and two.

Very helpful to see you posting these occasional snippets, but I do think that they need to come with:

  1. A clear link to the basics of how to install and run them, and
  2. a consistent name which identifies which language they are in, and which of the two possible JavaScript contexts they can run in.

(I have noticed for example, that many assume that even JXA code, let alone OmniJS code, is executed in a browser context, and will have access to the DOM etc)

1 Like

I am so glad you are here and that you are you! Excellent feedback, thank you.

Let me see if i can address your comments:

  1. RE: Omni Automation vs OmniJS • The official name for the dual-platform (macOS/iOS) JavaScript implementation in Omni software is “Omni Automation.” There is no OmmiJS, which was a project name that unfortunately has gained some traction. Hence, my use of the phrase “Omni Automation script” when describing an automation script.
    You are absolutely correct in stating that there is confusion about the various scripting implementations in Omni software. And while the opening page of https://omni-automation.com details the difference between Omni’s AppleScript/JXA implementation and Omni Automation, this distinction needs to be more visible and supported in other documentation.

  2. Omni Automation scripts are harder to debug and run outside of the console. • Again, a valid statement. At this time there is no stand-alone editor like Coda that supports the writing and debugging of Omni Automation scripts and plugins. Although the web consoles and clickable examples and templates on the website help make it easier to create and use Omni Automation scripts, it’s not the same as a robust editor application. To make it easier to use scripts and plugins, I’m implementing a new Install Plug-In button in some script examples that when activated guide the user in installing a plugin version of the script for either iOS and macOS. The install script should sense your system and prompt accordingly. This page has some examples of the install button: https://omni-automation.com/omnioutliner/selection.html which will hopefully soon be implemented site-wide ;-)

  3. Assigning scripts to keystrokes • Actually, assigning keystrokes to Omni Automation scripts is the same as with AppleScript or JXA. I recently posted a video about this topic: https://twitter.com/MACAUTOMATION/status/959256500689448961

But the main point of your comments is spot on: the messaging and documentation for Omni Automation could benefit from a consistent and clear approach. I’ll be sure to add reference links to my posted examples ;-) For example, to the iOS tutorial for OmniOutliner: https://omni-automation.com/tutorial/oo-ios/index.html And that a more robust development environment would be beneficial.

In support of Omni Automation, I must say that it has significant benefits, especially in speed. And with the apply() method for the rootItem and rootNode, processing every item in an outline requires dramatically less code than the other languages. And with Omni Automation URLs, the integration with the HTML DOM, and applications like FileMaker Pro is a real bonus! https://omni-automation.com/omnigraffle/filemaker/index.html

Thank you again for your comments and please keep the ideas and suggestions coming!

– SAL

o summarise

The splitting of Omni (indeed Apple platform(s)) scripting into two idioms (AppleScript and JavaScript for Automation) is still not widely or fully digested.
The further splitting of JavaScript scripting for for Omni apps into two APIs and two evaluation contexts is even less widely known or understood
Splitting even the nomenclature of the latest bifurcation into omniJS vs “Omni Automation” (which sounds as if it could mean AppleScript, JavaScript for Automation, or omniJS, seems a bit unlikely to help with points one and two.

Very helpful to see you posting these occasional snippets, but I do think that they need to come with:

A clear link to the basics of how to install and run them, and
a consistent name which identifies which language they are in, and which of the two possible JavaScript contexts they can run in.

(I have noticed for example, that many assume that even JXA code, let alone OmniJS code, is executed in a browser context, and will have access to the DOM etc)

There is no OmmiJS

Yes, Ken mentioned on Twitter that he’s recently been encouraging ‘Omni Automation’ in lieu of omniJS.

A slightly messy proposal, though, given that the core is:

omnigraffle:///omnijs-run?
omnioutliner:///omnijs-run?
etc ...

Re your video and the limited issue of keystrokes:

assigning keystrokes to Omni Automation scripts is the same as with AppleScript or JXA

Script menu ? FastScripts etc ? Toolbar buttons ?

the integration with the HTML DOM

There is none.

These new omniJS JSContext interfaces are excellent, and also fast, but there is no integration with the DOM.

You are thinking of links ? The Document Object Model is not exposed at all in non-browser JSContexts.

I think that claim, or that form of words, might risk confusing people.

For actual integration with the Document Object Model (completely absent in omniJS) you should probably look at something like the Keyboard Maestro ‘Custom prompt’ actions.

Yes, Toobar buttons are supported for actions.

In the header for a solitary action, you indicate the title for the action in the automation menu and for the toolbar button:

/{
“type”: “action”,
“targets”: [“omnioutliner”],
“author”: “Your Name or Company”,
“description”: “Description of this action.”,
“label”: “The menu item text”,
“paletteLabel”: “Palette Text”
}
/

See the bottom of this page: https://omni-automation.com/actions/index.html

In Plug-Ins there are three label versions for toolbar buttons and menu:

“label” = “About this PlugIn…”;
“shortLabel” = “About”;
“mediumLabel” = “About PlugIn”;
“longLabel” = “Information about this PlugIn”;

RE: integration with HTML, perhaps I should use different wording? As the many examples posted on the site demonstrate, Omni Automation scripts can interact well with HTML content, extracting and passing data from HTML as well as being triggered by HTML interface elements. A smoother way to describe that interaction would be useful.

You can run Omni Automation scripts from the system-wide macOS Script Menu (or FastScripts). They must be saved as URLs executed by a wrapping AppleScript (or JXA) that calls the “open location” scripting addition:

open location “omnigraffle:///omnijs-run?script=var%20aRect%20%3D%20new%20Rect%28100%2C100%2C200%2C200%29%0Avar%20aFillColor%20%3D%20Color%2ERGB%280%2C%200%2C%201%2C%201%29%0Avar%20aStrokeColor%20%3D%20Color%2Ered%0Acnvs%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%0Avar%20aShape%20%3D%20cnvs%2EaddShape%28%27Circle%27%2CaRect%29%0AaShape%2EstrokeThickness%20%3D%2012%0AaShape%2EfillColor%20%3D%20aFillColor%0AaShape%2EstrokeColor%20%3D%20aStrokeColor”

OR… you can do the encoding of the Omni Automation code in the AppleScript, like this:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set omniAutomationCode to "var aRect = new Rect(100,100,200,200)
var aFillColor = Color.RGB(0, 0, 1, 1)
var aStrokeColor = Color.red
cnvs = document.windows[0].selection.canvas
var aShape = cnvs.addShape('Circle',aRect)
aShape.strokeThickness = 12
aShape.fillColor = aFillColor
aShape.strokeColor = aStrokeColor"

set encodedOmniAutomationCode to encodeUsingPercentEncoding(omniAutomationCode)

set omniAutomationURL to "omnigraffle://localhost/omnijs-run?script=" & encodedOmniAutomationCode

open location omniAutomationURL

on encodeUsingPercentEncoding(sourceText)
	-- DOCUMENTATION: http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/uid/20000154-BCIBFDCB
	-- DOCUMENTATION: http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/uid/20000154-SW59
	
	-- create a Cocoa string from the passed AppleScript string, by calling the NSString class method stringWithString:
	set the sourceString to current application's NSString's stringWithString:sourceText
	-- apply the indicated transformation to the Cooca string
	set the adjustedString to the sourceString's stringByAddingPercentEscapesUsingEncoding:(current application's NSUTF8StringEncoding)
	-- coerce from Cocoa string to AppleScript string
	return (adjustedString as string)
end encodeUsingPercentEncoding

See this page about encoding to Omni Automation URLs using JavaScript (JXA):

https://omni-automation.com/script-links.html

function encodeForOmniAutomation(OmniAppName, scriptCode){
	appName = OmniAppName.toLowerCase()
	urlOpening = appName + "://localhost/omnijs-run?script="
	var encodedScript = encodeURIComponent(scriptCode)
	encodedScript = encodedScript.split("'").join("%27")
	encodedScript = encodedScript.split("(").join("%28")
	encodedScript = encodedScript.split(")").join("%29")
	encodedScript = encodedScript.split("!").join("%21")
	encodedScript = encodedScript.split("~").join("%7E")
	encodedScript = encodedScript.split(".").join("%2E")
	return urlOpening + encodedScript
}

Here’s a JXA script for encoding and running Omni Automation code:

app = Application.currentApplication()

app.includeStandardAdditions = true

var OmniAutomationScript = "aRect = new Rect(0, 0, 200, 200)\naColor = Color.RGB(0, 0, 1, 1)\naShape = canvases[0].addShape('Star', aRect)\naShape.fillColor = aColor"

var OmniAutomationURL = encodeForOmniAutomation('OmniGraffle', OmniAutomationScript)

app.openLocation(OmniAutomationURL)


function encodeForOmniAutomation(OmniAppName, scriptCode){
	appName = OmniAppName.toLowerCase()
	urlOpening = appName + "://localhost/omnijs-run?script="
	var encodedScript = encodeURIComponent(scriptCode)
	encodedScript = encodedScript.split("'").join("%27")
	encodedScript = encodedScript.split("(").join("%28")
	encodedScript = encodedScript.split(")").join("%29")
	encodedScript = encodedScript.split("!").join("%21")
	encodedScript = encodedScript.split("~").join("%7E")
	encodedScript = encodedScript.split(".").join("%2E")
	return urlOpening + encodedScript
}

And here is the basic JXA wrapper for running an Omni Automation URL:

app = Application.currentApplication()

app.includeStandardAdditions = true

var OmniAutomationURL = "omnigraffle://localhost/omnijs-run?script=var%20aRect%20%3D%20new%20Rect%28100%2C100%2C200%2C200%29%0Avar%20aFillColor%20%3D%20Color%2ERGB%280%2C%200%2C%201%2C%201%29%0Avar%20aStrokeColor%20%3D%20Color%2Ered%0Acnvs%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%0Avar%20aShape%20%3D%20cnvs%2EaddShape%28%27Circle%27%2CaRect%29%0AaShape%2EstrokeThickness%20%3D%2012%0AaShape%2EfillColor%20%3D%20aFillColor%0AaShape%2EstrokeColor%20%3D%20aStrokeColor"

app.openLocation(OmniAutomationURL)
1 Like

Thanks again for the great feedback.

A new page showing how to run Omni Automation scripts in JXA and AppleScript scripts has been added to Omni Automation website.

https://omni-automation.com/jxa-applescript.html

1 Like

Excellent. That seems a very helpful move.

A couple of comments on the specifics:

Here’s a JXA script for encoding and running Omni Automation code:

Perhaps your encodeForOmniAutomation function is bit complex and intimidating for a “Hello world example” ?

The additional [27, 28, 29, 21, 7E, 2E] are really only needed on special occasions when a URL is pasted into Apple Mail (I have personally never yet done that even once – it’s not needed in Hello World territory).

It might usefully declutter and clarify to hold that in reserve for the moment.

For the Hello World case we can more simply write something like:

// strURL :: String
const strURL = 'omnioutliner:///omnijs-run?script=' +
    encodeURIComponent(
        '(' + omniJS_OOContext + ')()'
    );

Where omniJS_OOContext is the name of a function in the code.

(You could also have an additional function for the Mail case – with demo of use – somewhere on hand, e.g. sth like the snippet below)

// strURL :: String
const strURL = 'omnioutliner:///omnijs-run?script=' +
    extraEncodesForMail(
        encodeURIComponent(
            '(' + omniJS_OOContext + ')()'
        )
    );

Again re:

Here’s a JXA script for encoding and running Omni Automation code:

You show a hello world in which the user is apparently expected to manually stringify the omnijs code into a stunningly long quoted line …

Hard to think of anything more burdensome and perplexing for a first-time user :-)

JavaScript automatically stringifies the code of any function named in a concatenation, and simply letting JS do that would impose much less work on the user, and probably be less daunting and peculiar too:

// strURL :: String
const strURL = 'omnioutliner:///omnijs-run?script=' +
    encodeURIComponent(
        '(' + omniJS_OOContext + ')()'
    );

TaskPaper’s documentation suggests a best practice here - allow the user to format their omnijs code intelligibly, in the way they prefer, and just clearly bracket (with prominent comments ) which code is omnijs and which is JXA:

(() => {
 
    // OMNIJS CONTEXT --------------------------------------------------------

    // omniJS_OOContext :: () -> [String]
    const omniJS_OOContext = () =>
        rootItem.apply(
            x => x.note !== '' ? (
                x.note = x.note + '\n'
            ) : ''
        );


    // JAVASCRIPT FOR AUTOMATION CONTEXT -------------------------------------

    // standardAdditions :: () -> Application
    const standardAdditions = () =>
        Object.assign(Application.currentApplication(), {
            includeStandardAdditions: true
        });

    // strURL :: String
    const strURL = 'omnioutliner:///omnijs-run?script=' +
        encodeURIComponent(
            '(' + omniJS_OOContext + ')()'
        );

    // Or if the URL might be pasted into Mail,
    // you can apply an extra layer of encoding as in:

    // strURLForMail :: String
    const strURLForMail = 'omnioutliner:///omnijs-run?script=' +
        extraEncodesForMail(
            encodeURIComponent(
                '(' + omniJS_OOContext + ')()'
            )
        );

    // extraEncodesForMail :: String -> String
    function extraEncodesForMail(strURLForMail) {
        return "'()!~.".split('')
            .reduce(
                (url, c) => url.replace(
                    RegExp('\\' + c, 'g'), // From global regex for character
                    '%' + c.codePointAt(0) // to percent and Hex code.
                    .toString(16)
                    .toUpperCase()
                ),
                strURL
            );
    }

    // Run the omnijs-run? url
    standardAdditions()
        .openLocation(strURL);
})();

Yes, Toolbar buttons are supported for actions.

The route from a forum-pasted snippet to a keystroke or toolbar button is the same for omniJS as for AS and JXA ?
You think so ?

In AS or JXA we can:

  • Save a snippet from Script Editor to a script folder, and
  • find it in a system standard script menu.

We can do the same with omnijs-run urls, or forum-pasted omnijs snippets ?

I may well have missed something, but my experience of omnijs code is that before it can even become an action we have to learn how to create plugins, and develop action handlers for them …

https://omni-automation.com/actions/index.html

Perhaps, though, there is some shorter route (more similar to that of AS / JXA) that has evaded me ?

If not, I’m not sure that we would really be helping users much by glossing too quickly over the difference between saving a snippet in a .scpt file and learning how to develop plugins and debug actions.

omnijs-run code is excellent, and deserves to move into mainstream use, but that simply won’t happen unless:

  1. The real accessibility of the Hello World stage is significantly improved (rather than simply glossed over with reference to assigning keys and buttons pre-existing plugin ‘actions’)
  2. a simple mechanism is developed for returning a value from code (see the 1Writer and Drafts JSContexts on iOS, and the TaskPaper JSContext on macOS)
  3. the whole project is re-imagined from a user perspective, and gently disengaged from a rather constricting and inflexible technical attachment to total dependence on a URL mechanism, even for basic code evaluation.
1 Like

It would be very helpful to list the omniJS / Omni Automation equivalents of:

1. Code snippet -> script in toolbar (AppleScript or JavaScript for Automation)

  1. Paste Hello World snippet into Script Editor
  2. Save As ~/Library/Application Scripts/com.omnigroup.OmniOutliner5/helloWorld.scpt
  3. OmniOutliner5: Customize Toolbar > drag Script:HelloWorld icon into toolbar

03


2. Code snippet -> menu item (AppleScript or JavaScript for Automation)

Assuming Script Editor > Preferences > General > Show Script menu in menu bar

  1. Paste Hello World snippet into Script Editor
  2. Save As ~/Library/Scripts/Applications/OmniOutliner/helloWorld.scpt
  3. In OmniOutliner, click on menubar Scripts icon.

16


3. Code snippet -> keyboard shortcut (AppleScript or JavaScript for Automation)

  • Automator, Sys Prefs route …
  • Keyboard Maestro route … (paste + assign)
  • FastScripts route … (save to + assign)

15


Not forgetting of course, that in all these cases, the user of JXA or AS snippets can immediately view, adjust, and retest the source code, in a tight and simple cycle, without being expected to manually reverse or restore percent-encoding of a URL at every stage, and without breaking connections to toolbar buttons or shortcut assignments.

1 Like

Creating solitary action plugins in Omni Automation is not difficult and they can be edited at anytime in TextEdit, BBEdit, or any text editor application that can handle plain text.

Using the template provided at the bottom of https://omni-automation.com/actions/index.html (shown below) you simply fill out the metadata info at the top, add validation code, and action code. Save and place in Plug-Ins folder opened from the Automation menu. You can also put them in your OmniPresence folder as well.

/*{
	"type": "action",
	"targets": ["omnigraffle","omnioutliner"],
	"author": "Your Name or Company",
	"description": "Description of this action.",
	"label": "The menu item text",
	"paletteLabel": "Palette Text"
}*/

var _ = function(){
	
	var action = new PlugIn.Action(function(selection, sender) {
		// action code
	});

	action.validate = function(selection, sender) {
		// validation code
		return true
	};
	
	return action;
}();
_;

For example, the information on this page https://omni-automation.com/omnioutliner/selection.html details how to use the selection object in OmniOutliner to refine the validation and action routines of an action.

The example script on that webpage for balancing the width of columns shows how the validation routine can streamline the script code to only contain the necessary processing statements.

BTW, if you click the Action Console button, the example script will open into a web console as a Omni Automation action! You can save the code to file by providing a file name and pressing the Save button.

/*{
	"type": "action",
	"targets": ["omnioutliner"],
	"author": "Nyhthawk Productions",
	"description": "Adjust the width of selected columns to be the same.",
	"label": "Balance Widths of Selected Columns",
	"paletteLabel": "Balance Column Widths"
}*/

var _ = function(){
	
	var action = new PlugIn.Action(function(selection, sender) {
		// action code
		// selection options: columns, document, editor, items, nodes, styles
		selectedColumns = selection.columns
		columnCount = selectedColumns.length
		widths = selectedColumns.map(function(col){
			return editor.widthForColumn(col)
		})
		total = widths.reduce(
			function(total,num){return total + num}, 
		0)
		avgWidth = total/columnCount
		avgWidth = Number(avgWidth.toFixed(0))
		selectedColumns.forEach(
			function(col){editor.setWidthForColumn(col,avgWidth)}
		)
	});

	action.validate = function(selection, sender) {
		// validation code
		// selection options: columns, document, editor, items, nodes, styles
		if(selection.columns.length > 1){return true} else {return false}
	};
	
	return action;
}();
_;
1 Like

Shouldn’t OmniOutliner’s evaluate javascript command not be mentioned as a way to run an OmniJS script via AppleScript/JXA?

2 Likes

That’s excellent – when was it added ?

I remember talk of work on it, and never noticed it slipping in. It does indeed evaluate code in a JS Context that exposes the omniJS objects and functions:

AppleScript

tell application "OmniOutliner"
    tell front document
        evaluate javascript ("Object.getOwnPropertyNames(this).join('\\n')")
    end tell
end tell

Tho I haven’t yet succeeded in doing it from JXA, which is where its really needed, so that omniJS code can be properly edited and formatted, and evaluated without additional complications of character escaping.

Application('OmniOutliner').documents.at(0).evaluateJavascript("2+2")

Application('OmniOutliner').evaluateJavascript("2+2")

and at this stage the method still crashes the app (from AS and from JXA) if asked to evaluate the JS string ‘this’.

Promising, nevertheless. It’s exactly what is needed.

UPDATE working now - once the JSContext has been through an upset, it needs to be reinitialized.

omniJS (‘Omni Automation’) code evaluated from JavaScript for Automation (JXA)

(() => {
    'use strict';

    // OMNIJS CODE -----------------------------------------------------------

    const omniJSContext = () =>
        Object.getOwnPropertyNames(this)
        .join('\n');

    // JXA CODE --------------------------------------------------------------

    return Application('OmniOutliner')
        .evaluateJavascript(
            '(' + omniJSContext + ')()'
        );
})();
// -->
ColumnArray
Infinity
NaN
undefined
parseFloat
isNaN
isFinite
escape
unescape
decodeURI
decodeURIComponent
encodeURI
encodeURIComponent
EvalError
ReferenceError
SyntaxError
URIError
Proxy
JSON
Math
Atomics
console
Int8Array
Int16Array
Int32Array
Uint8Array
Uint8ClampedArray
Uint16Array
Uint32Array
Float32Array
Float64Array
DataView
Set
Date
Boolean
Number
WeakMap
WeakSet
parseInt
Object
Function
Array
RegExp
RangeError
TypeError
ArrayBuffer
SharedArrayBuffer
String
Symbol
Error
Map
Promise
eval
Intl
Reflect
Calendar
Data
Editor
ItemPosition
Enumeration
NamedStyle
MenuItem
Locale
Text
Version
NamedStylePosition
Console
ItemTreeNode
Formatter
FileType
LigatureStyle
TextComponent
FileWrapper
Alert
Rect
Style
ColorSpace
Outline
NoteDisplay
State
Document
Timer
URL
EditorColumnPosition
Point
PlugIn
Size
Selection
OutlineDocument
Application
Decimal
Email
Color
Item
UnderlineAffinity
TreeNode
EnumerationMemberPosition
UnderlineStyle
LineCap
SortOrdering
TimeZone
Pasteboard
TextAlignment
Image
ToolbarItem
WritingDirection
UnderlinePattern
Column
app

And OmniGraffle has the same method.

So the answer is that, given the ability to return a value to JXA and AS:

  1. actions and plugins (tho they clearly have their uses) are probably an irrelevance for day to day work, and for the exchange of small scripting samples.
  2. We can now write data exporters (OO to MD, OG to JSON etc etc) in omniJS code (at least on the macOS side) without any need for all that all URL encoding and decoding business.
  3. What we need (I presume we don’t yet have it ?) is an analogue of .evaluateJavaScript() on the iOS side, in the same manner as 1Writer and Drafts.

Sigh of relief, and, more importantly, a thunderous round of applause for the authors of .evaluateJavaScript()

( and many thanks to @svenl for quietly pointing out that it’s already there :-)

Still crashing a bit … but I do feel more optimistic :-)

Even just a JSON return string would be enough.

(() => {
    'use strict';

    // OMNIJS CODE -----------------------------------------------------------
        
    const JSContext_OO = () =>
        rootItem.apply(x => x.note = (x.note + '\n'));

    // JXA CODE --------------------------------------------------------------

    return Application('OmniOutliner')
        .evaluateJavascript(
            '(' + JSContext_OO + ')()'
        );
})();