Skip to main content

AppleScript and OSA

Open Scripting Architecture (OSA)1 enables macOS app automation with scripts. OSA originally supported the "AppleScript" language. Modern macOS releases (OSX 10.10 and later) natively support JavaScript scripts using "JXA"2.

SheetJS is a JavaScript library for reading and writing data from spreadsheets.

This demo uses SheetJS in OSA Scripts to pull data from a spreadsheet. We'll explore how to use SheetJS libraries in AppleScript and JavaScript scripts. The "Complete Demo" parses workbooks and generates CSV rows.

Tested Environments

This demo was tested in the following environments:

macOSLanguageDate
14.5AppleScript (OSA)2024-06-30
14.5JavaScript (JXA)2024-06-30

Integration details​

The SheetJS Standalone scripts can be parsed and evaluated from the JS engine. Once evaluated, the XLSX global will be defined. A JS stub can expose methods from AppleScript scripts.

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.

  1. Download the SheetJS Standalone script and test file. Move both files to the project directory:
curl -LO https://docs.sheetjs.com/pres.numbers
curl -LO https://cdn.sheetjs.com/xlsx-0.20.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]]));
}
  1. Make the script executable:
chmod +x sheetosa.js
  1. Run the script, passing the path to the test file as an argument:
./sheetosa.js pres.numbers

If successful, CSV rows from the first worksheet will be printed:

Name,Index
Bill Clinton,42
GeorgeW Bush,43
Barack Obama,44
Donald Trump,45
Joseph Biden,46

Footnotes​

  1. See "Introduction to AppleScript Overview" in the Apple Developer documentation for more details. ↩

  2. See "Introduction to JavaScript for Automation Release Notes" in the Apple Developer documentation for more details. ↩