Skip to main content

AppleScript and OSA

Open Scripting Architecture (OSA), a built-in feature in macOS introduced in 1993, enables users to communicate with applications with a standardized language and grammar. macOS releases starting from Yosemite (OSX 10.10) include native support for scripting with JavaScript.

The Standalone scripts can be parsed and evaluated from the JS engine. Once evaluated, the XLSX variable is available as a global. A JS stub can expose methods from AppleScript scripts.

note

This demo was last tested on 2023 April 18 in macOS Monterey.

Integration details

The following snippet reads a file into a binary string:

ObjC.import("Foundation");
function get_bstr(path) {
/* create NSString from the file contents using a binary encoding */
var str = $.NSString.stringWithContentsOfFileEncodingError(path, $.NSISOLatin1StringEncoding, null);
/* return the value as a JS object */
return ObjC.unwrap(str);
}

Loading the Library

Assuming the standalone library is in the same directory as the source file, the script can be evaluated with eval:

var src = get_bstr("./xlsx.full.min.js");
eval(src);

Parsing Files

The same method can be used to read binary strings and parse with type: "binary":

var file = get_bstr("./pres.numbers");
var wb = XLSX.read(file);

Complete Demo

This example will read from a specified filename and print the first worksheet data in CSV format.

0) Download the standalone script and test file:

curl -LO https://sheetjs.com/pres.numbers
curl -LO https://cdn.sheetjs.com/xlsx-0.19.3/package/dist/xlsx.full.min.js

1) Save the following script to sheetosa.js:

sheetosa.js
#!/usr/bin/env osascript -l JavaScript

ObjC.import("Foundation");
function get_bstr(path) {
var str = $.NSString.stringWithContentsOfFileEncodingError(path, $.NSISOLatin1StringEncoding, null);
return ObjC.unwrap(str);
}
eval(get_bstr("./xlsx.full.min.js"));

function run(argv) {
var filedata = get_bstr(argv[0]);
var wb = XLSX.read(filedata, { type: "binary" });
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
}

2) Make the script executable:

chmod +x sheetosa.js

3) Run the script, passing the path to the test file as an argument:

./sheetosa.js pres.numbers