From e197ed24c86098e2110f4293665a47d2df79ae65 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Tue, 18 Apr 2023 16:26:59 -0400 Subject: [PATCH] osa --- docz/docs/03-demos/04-static/10-astro.md | 8 +- docz/docs/03-demos/05-mobile/05-capacitor.md | 8 +- docz/docs/03-demos/07-data/09-alasql.md | 2 +- docz/docs/03-demos/10-extensions/05-osa.md | 247 +++++++++++++++++++ docz/docusaurus.config.js | 2 +- 5 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 docz/docs/03-demos/10-extensions/05-osa.md diff --git a/docz/docs/03-demos/04-static/10-astro.md b/docz/docs/03-demos/04-static/10-astro.md index b97ac2c..c145b3e 100644 --- a/docz/docs/03-demos/04-static/10-astro.md +++ b/docz/docs/03-demos/04-static/10-astro.md @@ -64,12 +64,12 @@ This data loader returns Base64 strings: ```ts title="src/env.d.ts" /// declare module '*.numbers' { - const data: string; - export default data; + const data: string; + export default data; } declare module '*.xlsx' { - const data: string; - export default data; + const data: string; + export default data; } ``` diff --git a/docz/docs/03-demos/05-mobile/05-capacitor.md b/docz/docs/03-demos/05-mobile/05-capacitor.md index 5be412a..af02d95 100644 --- a/docz/docs/03-demos/05-mobile/05-capacitor.md +++ b/docz/docs/03-demos/05-mobile/05-capacitor.md @@ -183,10 +183,10 @@ The following lines must be added to `ios/App/App/Info.plist`: - UIFileSharingEnabled - - LSSupportsOpeningDocumentsInPlace - + UIFileSharingEnabled + + LSSupportsOpeningDocumentsInPlace + CFBundleDevelopmentRegion ``` diff --git a/docz/docs/03-demos/07-data/09-alasql.md b/docz/docs/03-demos/07-data/09-alasql.md index 80a1b2c..ce15629 100644 --- a/docz/docs/03-demos/07-data/09-alasql.md +++ b/docz/docs/03-demos/07-data/09-alasql.md @@ -77,7 +77,7 @@ function SheetJSAlaSQL() { if(typeof alasql=="undefined") return setRows([{Nom:"alasql undefined"}]); const blob = await (await fetch(url)).blob(); const data = URL.createObjectURL(blob); - const res = await alasql.promise(q1,[data]); + const res = await alasql.promise(q1,[data]); setRows(res); await alasql.promise(q2, [res]); }, []); diff --git a/docz/docs/03-demos/10-extensions/05-osa.md b/docz/docs/03-demos/10-extensions/05-osa.md new file mode 100644 index 0000000..c708e1e --- /dev/null +++ b/docz/docs/03-demos/10-extensions/05-osa.md @@ -0,0 +1,247 @@ +--- +title: AppleScript and OSA +pagination_prev: demos/cloud/index +pagination_next: demos/bigdata/index +--- + +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](/docs/getting-started/installation/standalone) 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 2022 April 18 in macOS Monterey. + +::: + +## Integration details + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +The following snippet reads a file into a binary string: + +```js +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`: + +```js +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"`: + +```js +var file = get_bstr("./pres.numbers"); +var wb = XLSX.read(file); +``` + + + + +The core idea is to push the processing logic to a stub JS file. + +_JS Stub_ + +The JS stub will be evaluated in the JavaScript context. The same technique from +the JavaScript section works in the stub: + +```js +ObjC.import("Foundation"); + +function get_bstr(path) { + var str = $.NSString.stringWithContentsOfFileEncodingError(path, $.NSISOLatin1StringEncoding, null); + return ObjC.unwrap(str); +} + +/* this will be called when AppleScript initializes the JS engine */ +eval(get_bstr("./xlsx.full.min.js")); +``` + +It is more efficient to offload as much work as possible into the stub. For +example, this function parses a workbook file from the filesystem and generates +a CSV without passing intermediate values back to AppleScript: + +```js +/* this method will be exposed as `wb_to_csv` */ +function wb_to_csv(path) { + /* read file */ + var filedata = get_bstr(path); + var wb = XLSX.read(filedata, { type: "binary" }); + return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]); +} +``` + +_Loading the Stub_ + +Assuming the stub is saved to `xlsx.stub.js`, the following handler creates a +context and evaluates the standalone library: + +```applescript +on getContext() + -- get contents of xlsx.stub.js + set UnixPath to POSIX path of ((path to me as text) & "::") + set libpath to POSIX path of (UnixPath & "xlsx.stub.js") + set {src, err} to current application's NSString's stringWithContentsOfFile:libpath encoding:(current application's NSISOLatin1StringEncoding) |error|:(reference) + if src is missing value then error (err's localizedDescription()) as text + + -- create scripting context and evaluate the stub + set lang to current application's OSALanguage's languageForName:"JavaScript" + set osa to current application's OSAScript's alloc()'s initWithSource:src language:lang + return osa +end getContext +``` + +_Evaluating JS Code_ + +When calling a function, the result is an array whose first item is the value of +the evaluated code. A small helper function extracts the raw result: + +```applescript +on extractResult(res) + return item 1 of ((current application's NSArray's arrayWithObject:res) as list) +end extractResult +``` + +With everything defined, `executeHandlerWithName` will run functions defined in +the stub. For example: + +```applescript +set osa to getContext() +set {res, err} to osa's executeHandlerWithName:"wb_to_csv" arguments:{"pres.numbers"} |error|:(reference) +extractResult(res) +``` + + + + +## 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: + +```bash +curl -LO https://sheetjs.com/pres.numbers +curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js +``` + + + + +1) Save the following script to `sheetosa.js`: + +```js title="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: + +```bash +chmod +x sheetosa.js +``` + +3) Run the script, passing the path to the test file as an argument: + +```bash +./sheetosa.js pres.numbers +``` + + + + +1) Save the following script to `xlsx.stub.js`: + +```js title="xlsx.stub.js" +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 wb_to_csv(path) { + var filedata = get_bstr(path); + var wb = XLSX.read(filedata, { type: "binary" }); + return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]); +} +``` + +2) Save the following script to `sheetosa.scpt`: + +```applescript title="sheetosa.scpt" +#!/usr/bin/env osascript +use AppleScript version "2.7" +use scripting additions +use framework "Foundation" +use framework "OSAKit" + +set osa to getContext() +set {res, err} to osa's executeHandlerWithName:"wb_to_csv" arguments:{"pres.numbers"} |error|:(reference) +extractResult(res) + +on getContext() + set UnixPath to POSIX path of ((path to me as text) & "::") + set libpath to POSIX path of (UnixPath & "xlsx.shim.js") + set {src, err} to current application's NSString's stringWithContentsOfFile:libpath encoding:(current application's NSISOLatin1StringEncoding) |error|:(reference) + + set lang to current application's OSALanguage's languageForName:"JavaScript" + set osa to current application's OSAScript's alloc()'s initWithSource:src language:lang + return osa +end getContext + +on extractResult(res) + return item 1 of ((current application's NSArray's arrayWithObject:res) as list) +end extractResult +``` + +3) Make the script executable: + +```bash +chmod +x sheetosa.scpt +``` + +3) Run the script (it is hardcoded to read `pres.numbers`): + +```bash +./sheetosa.scpt +``` + + + \ No newline at end of file diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js index d3a3c94..a217475 100644 --- a/docz/docusaurus.config.js +++ b/docz/docusaurus.config.js @@ -142,7 +142,7 @@ const config = { prism: { theme: lightCodeTheme, darkTheme: darkCodeTheme, - additionalLanguages: [ "swift", "java", "csharp", "perl", "ruby", "cpp" ], + additionalLanguages: [ "swift", "java", "csharp", "perl", "ruby", "cpp", "applescript" ], }, liveCodeBlock: { playgroundPosition: 'top'