Returning data from Omni Automation script

I’m trying to essentially export a lot of my OmniFocus data from the command line, so I tried to make an Omni Automation script that returns the data I want. However, I can’t seem to get it to return any data. Is there any way to do this, or do I have to use JXA instead?

omniJS code can be passed in and evaluated by the osascript interface (i.e. from JXA or AppleScript) using the .evaluateJavascript method, which expects a code string argument.

(A string for a top level JS function object can, of course, be derived using the .toString() method)

.evaluateJavascript can return a string value to the caller, which could be an osascript command line in the shell.

Broadly:

Application("OmniFocus").evaluateJavascript("2+2")

or

(() => {
    "use strict";

    const f = () => 2 + 2;
    
    return Application("OmniFocus").evaluateJavascript(
       `(${f.toString()})()`
    );
})()

or, equivalently, allowing automatic coercion from Function to String by the string template context:

(() => {
    "use strict";

    // Top level function for an omniJS context
    const f = () => 2 + 2;
    
    return Application("OmniFocus").evaluateJavascript(
       `(${f})()`
    );
})()

Note that I haven’t tried any of this for a while, but it used to blow up if one tried to pass back a value of any type other than String from the omniJS context. Not sure whether that has been fixed since then.

That worked, thanks!

Here, I am using OmniFocus 4.2.1 and I can return a number and perform an operation with it:

(() => {
    'use strict';

    // OMNI JS CODE ---------------------------------------
    const omniJSContext = () => {
        return 2
    };


    // OmniJS Context Evaluation ------------------------------------------------
    return 0 < Application('OmniFocus').documents.length ? (
        Application('OmniFocus').evaluateJavascript(
            `(${omniJSContext})()`
        ) + 2
    ) : 'No documents open in OmniFocus.'
})();
1 Like

Thanks !

And having now tested, I see that non-atomic values too can generally be returned successfully these days.

An empty object seems to be a tricky edge case (it gets stringified to "[object Object]" in the example below) but empty objects are not very useful return values anyway :-)

Date values, similarly, do still have to be pre-stringified, to protect them from loss behind an uninformative "[object Object]" string.

The code below:

(() => {
    "use strict";

    // OMNI JS CODE ---------------------------------------
    const omniJSContext = () =>
        ({
            someObject: {},
            someArray: [],
            someDate: new Date()
        });

    // OmniJS Context Evaluation --------------------------
    const omnifocus = Application("OmniFocus");

    return 0 < omnifocus.documents.length
        ? omnifocus.evaluateJavascript(
            `(${omniJSContext})()`
        )
        : "No documents open in OmniFocus.";
})();

yields:

{"someArray":[], "someDate":[object Object], "someObject":[object Object]}

Dates apart, you could get around some limitations of this kind, if they proved relevant, by wrapping the return value in a call to JSON.stringify on the omniJS side, and applying JSON.parse to the result on the JXA side.

1 Like