├── .gitignore ├── Makefile ├── LICENSE.txt ├── README.md ├── tests.applescript └── json.applescript /.gitignore: -------------------------------------------------------------------------------- 1 | *.scpt 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | json.scpt: json.applescript 2 | osacompile -o json.scpt json.applescript 3 | 4 | test: json.scpt 5 | osascript tests.applescript 6 | 7 | .PHONY: test 8 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Alex Morega 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AppleScript JSON encoder 2 | 3 | AppleScript lacks a native way to generate JSON, which makes getting 4 | data out of scripts difficult. This script provides a basic JSON 5 | encoding capability, to serialize strings, integers, lists and 6 | dictionaries. 7 | 8 | ### Installation 9 | 10 | Build the `json.scpt` file by running `make`, copy it next to your 11 | script, and import it with the following code: 12 | 13 | ```applescript 14 | tell application "Finder" 15 | set json_path to file "json.scpt" of folder of (path to me) 16 | end 17 | set json to load script (json_path as alias) 18 | ``` 19 | 20 | Alternatively, just copy/paste the contents of `json.applescript` into 21 | your own script, and use it straight away. 22 | 23 | ### Usage 24 | 25 | To encode strings, numbers and lists: 26 | 27 | ```applescript 28 | json's encode("hellø world") 29 | -- "hell\u00f8 world" 30 | 31 | json's encode(13) 32 | -- 13 33 | 34 | json's encode({1, "2", {3, 4}}) 35 | -- [1, "2", [3, 4]] 36 | ``` 37 | 38 | Dictionaries are supported via a wrapper object: 39 | 40 | ```applescript 41 | set my_dict to json's createDict() 42 | my_dict's setkv("hello", {"world", 13}) 43 | json's encode(my_dict) 44 | -- {"hello": ["world", 13]} 45 | 46 | set my_dict_2 to json's createDictWith({ {"foo", "bar"}, {"baz", 22} }) 47 | json's encode(my_dict_2) 48 | -- {"foo": "bar", "baz": 22} 49 | ``` 50 | -------------------------------------------------------------------------------- /tests.applescript: -------------------------------------------------------------------------------- 1 | tell application "Finder" 2 | set json_path to file "json.scpt" of folder of (path to me) 3 | end 4 | set json to load script (json_path as alias) 5 | 6 | 7 | on assert_eq(a, b) 8 | if not a = b then 9 | set aq to quoted form of a as text 10 | set bq to quoted form of b as text 11 | error "values not equal:" & aq & " != " & bq 12 | end 13 | end 14 | 15 | 16 | assert_eq(json's hex4(0), "0000") 17 | assert_eq(json's hex4(1), "0001") 18 | assert_eq(json's hex4(11), "000b") 19 | assert_eq(json's hex4(2*16), "0020") 20 | assert_eq(json's hex4(65534), "fffe") 21 | assert_eq(json's hex4(65535), "ffff") 22 | assert_eq(json's hex4(65536), "0000") 23 | assert_eq(json's hex4(65537), "0001") 24 | 25 | assert_eq(json's encode(1), "1") 26 | assert_eq(json's encode(0), "0") 27 | 28 | assert_eq(json's encode(true), "true") 29 | assert_eq(json's encode(false), "false") 30 | 31 | assert_eq(json's encode("foo"), "\"foo\"") 32 | assert_eq(json's encode(""), "\"\"") 33 | assert_eq(json's encode("\n"), "\"\\u000a\"") 34 | assert_eq(json's encode("ș"), "\"\\u0219\"") 35 | assert_eq(json's encode("u" & "̈"), "\"u\\u0308\"") 36 | assert_eq(json's encode("\"bar\""), "\"\\\"bar\\\"\"") 37 | assert_eq(json's encode("\\"), "\"\\\\\"") 38 | 39 | assert_eq(json's encode({1, 2, 3}), "[1, 2, 3]") 40 | 41 | assert_eq(json's encode(json's createDict()), "{}") 42 | 43 | set dict to json's createDictWith({{"foo", "bar"}}) 44 | assert_eq(json's encode(dict), "{\"foo\": \"bar\"}") 45 | 46 | set dict2 to json's createDictWith({{"a", 13}, {"b", {2, "other", dict}}}) 47 | assert_eq(json's encode(dict2), "{\"a\": 13, \"b\": [2, \"other\", {\"foo\": \"bar\"}]}") 48 | 49 | log "ok" 50 | -------------------------------------------------------------------------------- /json.applescript: -------------------------------------------------------------------------------- 1 | on encode(value) 2 | set type to class of value 3 | if type = integer or type = boolean 4 | return value as text 5 | else if type = text 6 | return encodeString(value) 7 | else if type = list 8 | return encodeList(value) 9 | else if type = script 10 | return value's toJson() 11 | else 12 | error "Unknown type " & type 13 | end 14 | end 15 | 16 | 17 | on encodeList(value_list) 18 | set out_list to {} 19 | repeat with value in value_list 20 | copy encode(value) to end of out_list 21 | end 22 | return "[" & join(out_list, ", ") & "]" 23 | end 24 | 25 | 26 | on encodeString(value) 27 | set rv to "" 28 | set codepoints to id of value 29 | 30 | if (class of codepoints) is not list 31 | set codepoints to {codepoints} 32 | end 33 | 34 | repeat with codepoint in codepoints 35 | set codepoint to codepoint as integer 36 | if codepoint = 34 37 | set quoted_ch to "\\\"" 38 | else if codepoint = 92 then 39 | set quoted_ch to "\\\\" 40 | else if codepoint >= 32 and codepoint < 127 41 | set quoted_ch to character id codepoint 42 | else 43 | set quoted_ch to "\\u" & hex4(codepoint) 44 | end 45 | set rv to rv & quoted_ch 46 | end 47 | return "\"" & rv & "\"" 48 | end 49 | 50 | 51 | on join(value_list, delimiter) 52 | set original_delimiter to AppleScript's text item delimiters 53 | set AppleScript's text item delimiters to delimiter 54 | set rv to value_list as text 55 | set AppleScript's text item delimiters to original_delimiter 56 | return rv 57 | end 58 | 59 | 60 | on hex4(n) 61 | set digit_list to "0123456789abcdef" 62 | set rv to "" 63 | repeat until length of rv = 4 64 | set digit to (n mod 16) 65 | set n to (n - digit) / 16 as integer 66 | set rv to (character (1+digit) of digit_list) & rv 67 | end 68 | return rv 69 | end 70 | 71 | 72 | on createDictWith(item_pairs) 73 | set item_list to {} 74 | 75 | script Dict 76 | on setkv(key, value) 77 | copy {key, value} to end of item_list 78 | end 79 | 80 | on toJson() 81 | set item_strings to {} 82 | repeat with kv in item_list 83 | set key_str to encodeString(item 1 of kv) 84 | set value_str to encode(item 2 of kv) 85 | copy key_str & ": " & value_str to end of item_strings 86 | end 87 | return "{" & join(item_strings, ", ") & "}" 88 | end 89 | end 90 | 91 | repeat with pair in item_pairs 92 | Dict's setkv(item 1 of pair, item 2 of pair) 93 | end 94 | 95 | return Dict 96 | end 97 | 98 | 99 | on createDict() 100 | return createDictWith({}) 101 | end 102 | --------------------------------------------------------------------------------