Running my package json test command - the hard way

Sometimes it can be super handy to have a quick and dirty way of accessing your package json scripts. Maybe you just want to know what the right name to call is. For that jq is our friend.

cat package.json | jq '.scripts'

cat creates a stream of our package json file and pipes the stream to jq which gives us full access to query or manipulate the json.

Ok cool, so this will output something akin to the following

  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "lint": "eslint '*/**/*.{js,ts,tsx}'",
  "test": "jest --env=jsdom --testPathIgnorePatterns /.storybook/*/"

So we can clearly see our test command there. So a layman could just use their mouse (yuck, what an antipattern!) to highlight and then copy the command itself ready for use.

I say no. We must go further!

So first we can select the actual command we want.

cat package.json | jq '.scripts.test'
# returns
"jest --env=jsdom --testPathIgnorePatterns /.storybook/*/"

Ok nice, so next issue is those " marks. We can easily strip them with a good ol’ fashioned tr

cat package.json | jq '.scripts.test' | tr -d '"'
# returns 
jest --env=jsdom --testPathIgnorePatterns /.storybook/*/

Very nice, that’s the actual command right there. Crazy I know!

So how’s about we push that into our system’s clipboard?

cat package.json | jq '.scripts.test' | tr -d '"' | xclip -sel clipboard

Now you can paste that bad boy in any other program and you’re away 🚀

Beautiful Compositionality

This is possibly my favourite part of the Linux philosophy. Each of these tools does one thing well, and its up to us the humble power user to compose these commands together into a symphony of awesomeness.

Interactivity with FZF

Things can start to get really interesting when we incorporate a find and select into this flow.

cat package.json | jq '.scripts' | head -n -1 | tail -n +2 | fzf

So this will feed each script line into fzf - everyone’s favourite fuzzy finder.

Nice. But let’s take this a step further.

How about if we could fuzzy search over the available package.json scripts, with a preview of the command itself, and then finally run the highlighted script on select.

This is getting a bit crazy so we’ll split it over multiple lines, and I will break down each stage after.

cat package.json \
| jq '.scripts | keys' \
| head -n -1 \
| tail -n +2 \
| tr -d '"' \
| tr -d ',' \
| tr -d ' ' \
| fzf --preview="cat package.json | jq '.scripts[\"{}\"]' | tr -d '\"'" \
| xargs yarn

Its a bit of a beast, but it works!

So first off we’re using '.scripts | keys' in the first jq. This gets us the keys of the scripts object.

We then have some fun with head and tail to cut away the first and last lines of the array which is returned.

Next up, tr 3 of them in a row just to remove any characters we aren’t interested in displaying.

Piping that to fzf gives us fuzzy search over the items in that list, and the --preview option lets us pick what should be displayed in the right hand preview panel. The option takes a shell string with the currently highlighted record from the list injected wherever {} is seen.

So we search the package.json scripts again with jq this time picking the exact script currently selected in the fuzzy search. Cut that to size with tr again to get rid of those " (this time escaped as we’re already inside "

When the user hits enter on one of those record, fzf will pipe the selection to stdout so we catch this with xargs - which will append the piped input to the end of the command, and finally say we want to run yarn followed by the script.

So if we run this and select “test” say. Then the final result will be yarn test


All that’s left now is to release this as an npm package… ← Sarcasm.