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.'
})();
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.