macos
Version:
node.js module for interfacing with OSX 10.10 Javascript OSA Scripting
68 lines (56 loc) • 2.58 kB
JavaScript
var exec = require('child_process').exec;
// export function osa
// takes a function, any number of arguments, and a callback.
// It will run the function in the OSA environment, passing in any given arguements.
// that function is expected to return a single value, which will be passed back to the
// callback via stdout.
var consoleLogPrefix = '<brandonhorst:node-osa>';
var consoleLogSuffix = '</brandonhorst:node-osa>';
function extractLogs (stderr) {
var reg = new RegExp('^' + consoleLogPrefix + ' ([\\s\\S]*?) ' + consoleLogSuffix + '$', 'gm');
var matches = [];
var found;
while ((found = reg.exec(stderr)) !== null) {
matches.push(found[1]);
reg.lastIndex -= found[0].split(':')[1].length;
}
return matches.length > 0 ? matches.join('\n') : null;
}
module.exports = function osa (osaFunction) {
// get an array of arguments, excluding the osaFunction and the callback
var args = Array.prototype.slice.call(arguments, 1, arguments.length - 1);
// get a reference to the callback
var done = arguments[arguments.length - 1];
// conver these args to json
var jsonArgs = args.map(JSON.stringify);
// build a string to call osaFunction, pass in args, and evaulate to
// the JSON representation of the return value, then call it with osascript
var consoleLogPatch = 'var old = console.log; console.log = function () { Array.prototype.unshift.call(arguments, "' +
consoleLogPrefix + '"); Array.prototype.push.call(arguments, "' + consoleLogSuffix +
'"); old.apply(console, arguments); }; ';
var functionCallString = consoleLogPatch + 'JSON.stringify((' + osaFunction.toString() + ')(' + jsonArgs.join(',') + '));';
var escapedCall = functionCallString.replace(/^\s+/g, ' ').replace(/\n/g, '').replace(/'/g, "'\\''");
var executeString = "osascript -l JavaScript -e '" + escapedCall + "'";
exec(executeString, {maxBuffer: 1024 * 1024}, function (err, stdout, stderr) {
var result, newErr;
var log = extractLogs(stderr);
// if an error was thrown, it will go into err - just pass it through
if (err) {
done(err);
// if no error was thrown, anything returned will be in stdout
} else {
try {
if (stdout === '\n') {
done(null, undefined, log);
} else {
result = JSON.parse(stdout);
done(null, result, log);
}
// if nothing was in stdout (or it wasn't JSON), something went wrong
} catch (e) {
newErr = new Error('Function did not return an object: ' + e.message);
done(newErr);
}
}
});
};