{"id":849,"date":"2020-11-03T01:17:12","date_gmt":"2020-11-03T06:17:12","guid":{"rendered":"https:\/\/www.brunerd.com\/blog\/?p=849"},"modified":"2020-11-03T01:17:14","modified_gmt":"2020-11-03T06:17:14","slug":"secret-origins-the-jpt","status":"publish","type":"post","link":"https:\/\/www.brunerd.com\/blog\/2020\/11\/03\/secret-origins-the-jpt\/","title":{"rendered":"secret origins: the jpt"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\">On building a JSON tool for macOS <em>without<\/em> using Python, perl, or Ruby.<\/h4>\n\n\n\n<p>In my work as a Macintosh engineer and administrator I&#8217;ve noticed macOS has lacked a bundled tool for working with JSON at the command line. Where XML has its <code>xpath<\/code>, if your shell script needs some JSON chops, it&#8217;ll require an external binary like jq or something else scripted in Python, Ruby or perl using their JSON modules. The problem is, those runtimes have been <a rel=\"noreferrer noopener\" href=\"https:\/\/mjtsai.com\/blog\/2019\/06\/04\/scripting-languages-to-be-removed\/\" target=\"_blank\">slated for removal<\/a> from a future macOS. So I took that as challenge to devise a method to query and modify JSON data within shell scripts, that <em>didn&#8217;t<\/em> use one of those deprecated scripting runtimes and didn&#8217;t require an external binary dependency either. Could I achieve robust and native JSON parsing on a Mac by simply &#8220;living off the land&#8221;?<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Why not just re-install the runtimes when Apple deprecates them?<\/h4>\n\n\n\n<p>&#8220;Why limit yourself like this? Just re-install the runtimes and move on&#8221;, you may ask. Well, I&#8217;d like to think that limitations can inspire creativity but we should also consider there may be some <em>other<\/em> reasons why Apple is discontinuing the inclusion of those runtimes. Some may say, &#8220;Apple Silicon + macOS 11.0  is the perfect time for them to clean house&#8221;, to which I&#8217;d have to agree that&#8217;s a <em>very<\/em> good reason and likely a factor. Others could say they are looking to tighten the screws to keep out unsigned code: maybe, they <em>do<\/em> like to glue things shut! But really, I think it&#8217;s more akin to the web-plugins of yore like Java and Flash. Apple does not want to be the conduit for deploying 3rd party party runtimes which increase the attack surface of macOS. This seems like the most reasonable of the explanations. So, if you accept that Apple is attempting to <em>reduce<\/em> attack surface, why increase it by re-installing Python, Ruby, or perl, <em>just<\/em> so a transient script (like a Jamf Extension Attribute) can parse a JSON file? My answer to that, is you don&#8217;t. You play the hand you&#8217;re dealt. Game on!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Looking for truffles (in a very small back yard)<\/h4>\n\n\n\n<p>Despite having another project (<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/brunerd\/shui\" target=\"_blank\">shui<\/a>) that can output and invoke Applescript from within a shell scripts for generating user interfaces, I definitely knew that Applescript was <em>not<\/em> the way to go. Apple however, added to the languages Open Scripting Architecture (OSA) supports back in 2014 with OS X Yosemite (10.10), they added Javascript along with a bridge to the Cocoa Objective-C classes and they called it JXA: Javascript for Automation. This seemed like a promising place, so I started playing with <code>osascript<\/code> and figured out how to load files and read \/dev\/stdin using JXA, and while looking for an answer for garbled input from stdin I came upon a Japanese <a rel=\"noreferrer noopener\" href=\"https:\/\/translate.google.com\/translate?hl=&amp;sl=ja&amp;tl=en&amp;u=http%3A%2F%2Fpalepoli.skr.jp%2Fwp%2F2017%2F01%2F08%2Fjxa-and-javascriptcore-stdin%2F&amp;anno=2&amp;sandbox=1\" target=\"_blank\">blog<\/a> that mentioned <code><strong><a rel=\"noreferrer noopener\" href=\"https:\/\/trac.webkit.org\/wiki\/JSC\" target=\"_blank\">jsc<\/a><\/strong><\/code> the <a rel=\"noreferrer noopener\" href=\"https:\/\/trac.webkit.org\/wiki\/JavaScriptCore\" target=\"_blank\">JavaScriptCore<\/a> binary which resides in the <strong>\/System\/Library\/Frameworks<\/strong>\/ <strong>JavaScriptCore.framework<\/strong>. Arigato! Pay dirt! \ud83e\udd11  <code>jsc<\/code> does exactly what we need it to do: It can interpret Javascript passed as an argument, can access the filesystem and read from \/dev\/stdin, and best of all is in non-Private System level Framework that exists all the way back to OS X 10.4! Just the kind of foundation on which to build the tool. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Homesteading <code>jsc<\/code><\/h4>\n\n\n\n<p>The existence of <code>jsc<\/code> goes back all the way to OS X Tiger and it&#8217;s functionality has evolved over the years. In order to have a consistent experience in <code>jpt<\/code> from macOS 10.4 &#8211; 11.x+ a few polyfills had to be employed for missing functions, along with a few other workarounds regarding file loading, printing and exit codes (or lack thereof). Once those were addressed the <code>jsc<\/code> proved to be a highly optimized Javascript environment that&#8217;s blazingly fast. It spans 13 macOS releases and is even present in many Linux distros out-of-the-box (Ubuntu and CentOS) and can even be run on Windows when the Linux Subsytem is installed.<\/p>\n\n\n\n<p>With the host environment sorted, I began working with the original JSONPath code by <a rel=\"noreferrer noopener\" href=\"https:\/\/goessner.net\/articles\/JsonPath\/\" target=\"_blank\">Stefan Goessner<\/a> as the query language. I didn&#8217;t know about JSON Pointer yet so this strange beast was all I knew! It worked out really. I went full throttle into developing the &#8220;swiss army knife&#8221; of JSON tools. I really leaned into the Second System Effect, as described in the Mythical Man-month, it&#8217;s when you put every doodad, gizmo and doo-hicky in your 2nd product (my first simple JSON pretty-printer built in JS on <code>jsc<\/code>). Eventually though, after I reached a feature plateau, I came back around to the address the quirks of the original JSONPath code. I ended up rewriting signifigant chunks of JSONPath and released it as it&#8217;s own project: <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/brunerd\/jsonpath\" target=\"_blank\">brunerd JSONPath<\/a>. But I digress, let&#8217;s get back to the JSON Power Tool.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><code>jpt<\/code>: powers and abilities<\/h4>\n\n\n\n<p>At it&#8217;s most basic, <code>jpt<\/code> will format or &#8220;pretty print&#8221; any JSON given. <code>jpt<\/code> can also handle data retrieval from JSON document using either JSONPath or JSON Pointer syntax. JSONPath, while not a standard, is a highly expressive query language akin to XPath for XML, with poweful features like recursive search, filter expressions, slices, and unions. JSON Pointer on the other hand is narrower in focus, succint and easily expressed, and standardized but it does not offer any of the interogative features that I feel make JSONPath so intriguing. Finally, <code>jpt<\/code> can also modify values in a JSON document using standardized <a rel=\"noreferrer noopener\" href=\"https:\/\/tools.ietf.org\/html\/rfc6902\" target=\"_blank\">JSON Patch<\/a> operations like: add, remove, replace, copy, move, and test, as well as the also standardized <a rel=\"noreferrer noopener\" href=\"https:\/\/tools.ietf.org\/html\/rfc7396\" target=\"_blank\">JSON Merge Patch<\/a> operation. Altogether, the <code>jpt<\/code> can format, retrieve and alter JSON documents using only a bit of outer shell script plus a lot more Javascript on any macOS since 10.4! \ud83d\ude05<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Where can I get the <code>jpt<\/code>?<\/h4>\n\n\n\n<p>Stop by the project&#8217;s GitHub page at: <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/brunerd\/jpt\" target=\"_blank\">https:\/\/github.com\/brunerd\/jpt<\/a><\/p>\n\n\n\n<p>There you will find the full source and also a minified version of the <code>jpt<\/code> for inclusion within <em>your<\/em> shell scripts. Since it&#8217;s never compiled you can always peer inside and learn from it, customize it, modify it, or just tinker around with it (usually the <em>best<\/em> teacher).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Future Plans<\/h4>\n\n\n\n<p>There will undoubtedly be continued work on the <code>jpt<\/code>. Surely there are less than optimal routines, un-idiomatic idioms, edge cases not found, and features yet to be realized. But as far as the core functionality goes though, it&#8217;s fairly feature complete in my opinion. Considering that one of my top 10 StrengthsFinder qualities is &#8220;Maximizer&#8221;, the odds are pretty good, I&#8217;ll keep honing the <code>jpt<\/code>&#8216;s utility, size (smaller), and sharing more articles with examples on the kinds of queries and data alteration operations the <code>jpt<\/code> can so perform. Stay tuned!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On building a JSON tool for macOS without using Python, perl, or Ruby. In my work as a Macintosh engineer and administrator I&#8217;ve noticed macOS has lacked a bundled tool for working with JSON at the command line. Where XML has its xpath, if your shell script needs some JSON chops, it&#8217;ll require an external [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,19,38,37,41,12,39],"tags":[20,42,43,30,45,44,34,25,33,24,23],"class_list":["post-849","post","type-post","status-publish","format-standard","hentry","category-apple","category-bash","category-javascript","category-jpt","category-jsonpath","category-scripting","category-zsh","tag-bash","tag-javascript","tag-javascriptcore","tag-jpt","tag-jq","tag-jsc","tag-json","tag-macos","tag-os-x","tag-shell","tag-zsh"],"_links":{"self":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts\/849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/comments?post=849"}],"version-history":[{"count":10,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts\/849\/revisions"}],"predecessor-version":[{"id":862,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts\/849\/revisions\/862"}],"wp:attachment":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/media?parent=849"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/categories?post=849"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/tags?post=849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}