Know thy dependencies using jq

July 01, 2019 ■ 5 min read

Whenever we're working on any Javascript project whether it is backend or frontend, there are few important things for which you keep coming back to your project's package.json file. And, those are...

Yes, you guessed it right:

  • Dependencies : What are your primary 3rd party dependencies? What are the versions of those dependencies?
  • Scripts - How to run and build this project?

Wouldn't it be nice if instead of opening package.json file again and again to check for above things when required we could just run one command for the same purpose.

You might be thinking 🤔 and saying in your mind that:

Yes, Punit. I do just run one command to check for all these things that you are talking about.

cat package.json 
# OR
less package.json

Yeah, that works but this is how the output looks in your terminal:

{
  "name": "react-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "parcel src/index.html",
    "dev:mock": "cross-env API_MOCK=mock yarn dev",
    "format": "prettier \"src/**/*.*{js, html}\" --write",
    "lint": "tslint --project",
    "precommit": "lint-staged",
    "clear-build-cache": "rm -rf .cache dist"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.4.5",
    "@babel/plugin-proposal-class-properties": "^7.4.4",
    "@babel/preset-env": "^7.4.5",
    "@babel/preset-react": "^7.0.0",
    "@types/reach__router": "^1.2.4",
    "@types/react": "^16.8.22",
    "@types/react-dom": "^16.8.4",
    "cross-env": "^5.2.0",
    "husky": "^2.4.1",
    "lint-staged": "^8.2.1",
    "parcel-bundler": "^1.12.3",
    "prettier": "^1.18.2",
    "tslint": "^5.18.0",
    "tslint-config-prettier": "^1.18.0",
    "tslint-react": "^4.0.0",
    "typescript": "^3.5.2"
  },
  "dependencies": {
    "@emotion/babel-preset-css-prop": "^10.0.9",
    "@emotion/core": "^10.0.10",
    "@reach/router": "^1.2.1",
    "react": "16.8.4",
    "react-dom": "16.8.4"
  },
  "husky": {
    "hooks": {
      "pre-commit": "yarn precommit"
    }
  },
  "browserslist": [
    "last 2 Chrome versions",
    "last 2 ChromeAndroid versions",
    "last 2 Firefox versions",
    "last 2 FirefoxAndroid versions",
    "last 2 Safari versions",
    "last 2 iOS versions",
    "last 2 Edge versions",
    "last 2 Opera versions",
    "last 2 OperaMobile versions"
  ]
}

Above output is for a smaller React project. Imagine how big your package.json's file output generally becomes in your projects at work. Looking for dependencies and scripts in such large output doesn't seems like right thing to me.

Okay. Cool! So, what do you suggest then?

Wouldn't it be nice if type dependencies and I just see my dependencies instead of entire package.json's file output and similarly for scripts...?

Something like:

> scripts

And, you see output something like:

{
  "dev": "parcel src/index.html",
  "dev:mock": "cross-env API_MOCK=mock yarn dev",
  "format": "prettier \"src/**/*.*{js, html}\" --write",
  "lint": "tslint --project",
  "precommit": "lint-staged",
  "clear-build-cache": "rm -rf .cache dist"
}

Similarly, for dependencies you would type:

> dependencies

And, output would be as you would expect.

{
  "@emotion/babel-preset-css-prop": "^10.0.9",
  "@emotion/core": "^10.0.10",
  "@frontendmasters/pet": "^1.0.3",
  "@reach/router": "^1.2.1",
  "react": "16.8.4",
  "react-dom": "16.8.4"
}

How do we achieve it?

jq to the rescue. Using it we can slice, filter, map and transform any JSON data.

https://stedolan.github.io/jq/tutorial/

Using jq, we can do lot of operations on the JSON data. Check out jq's website to understand what different operations you could do on the JSON data using it. There are several great use cases of it.

Note:

I wouldn't be covering about how to use jq as tool to process JSON data in several ways in this post but just demonstrate one such use case which will help us achieve us what we're looking for in our situation as stated earlier.

Prior to running below commands you need to install jq in your system first.

If there is large JSON data payload you are getting from somewhere and you need to just check/extract some specific field details from it. You can do it using jq by running following command :

cat sample.json | jq .<name_of_the_field_you_are_looking_for>

Using above capability of jq we could extract just dependencies, devDependencies and scripts from our package.json's large output like below:

# For getting scripts used in package.json
cat package.json | jq '.scripts' 

# For getting dependencies used in package.json 
cat package.json | jq '.dependencies'

# For getting devDependencies used in package.json
cat package.json | jq '.devDependencies'

To avoid typing this long commands every time, we can create our own aliases for all these commands in .zshrc or .bashrc depending on whichever default system shell you're using.

In your rc file you would add aliases like following:

alias scripts="cat package.json | jq '.scripts'"
alias devDependencies="cat package.json | jq '.devDependencies'"
alias dependencies="cat package.json | jq '.dependencies'"

And, then whenever you need to check dependencies, devDependencies and scripts you could use the above set aliases to check for those specific things instead of outputting entire large package.json and looking for those things. Profit!!

Usage with above set aliases becomes:

# To find project's dependencies
> dependencies --> gives `dependencies` JSON object as output

# To find project's development dependencies
> devDependencies --> gives `devDependencies` JSON object as output

# To find scripts to use to run project locally or build it.
> scripts --> gives `scripts` JSON object as output

Closing Note

I've been using jq tool for quite a time but never thought about using it like this. Credit to Cameron Nokes's course on Egghead where I learned this trick. If you would like to check out other cool things we could do using bash I suggest you check out his course. Highly recommended!

Hope that was useful. Thanks for reading! 🚀

Want to be notified of similar posts? Follow me @punit__d on Twitter 🙂