forked from sheetjs/docs.sheetjs.com
		
	osa
This commit is contained in:
		
							parent
							
								
									5ff93dc4b7
								
							
						
					
					
						commit
						e197ed24c8
					
				@ -64,12 +64,12 @@ This data loader returns Base64 strings:
 | 
			
		||||
```ts title="src/env.d.ts"
 | 
			
		||||
/// <reference types="astro/client" />
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -183,10 +183,10 @@ The following lines must be added to `ios/App/App/Info.plist`:
 | 
			
		||||
<plist version="1.0">
 | 
			
		||||
<dict>
 | 
			
		||||
<!-- highlight-start -->
 | 
			
		||||
	<key>UIFileSharingEnabled</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>LSSupportsOpeningDocumentsInPlace</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
  <key>UIFileSharingEnabled</key>
 | 
			
		||||
  <true/>
 | 
			
		||||
  <key>LSSupportsOpeningDocumentsInPlace</key>
 | 
			
		||||
  <true/>
 | 
			
		||||
<!-- highlight-end -->
 | 
			
		||||
  <key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -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]);
 | 
			
		||||
  }, []);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										247
									
								
								docz/docs/03-demos/10-extensions/05-osa.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										247
									
								
								docz/docs/03-demos/10-extensions/05-osa.md
									
									
									
									
									
										Normal file
									
								
							@ -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';
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="osa">
 | 
			
		||||
  <TabItem value="js" label="JavaScript">
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="as" label="AppleScript">
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<Tabs groupId="osa">
 | 
			
		||||
  <TabItem value="js" label="JavaScript">
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
  <TabItem value="as" label="AppleScript">
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
  </TabItem>
 | 
			
		||||
</Tabs>
 | 
			
		||||
@ -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'
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user