How to add dependencies into package.json with jq

54 Views Asked by At

I want to add package dependencies to the package.json file by bash script using jq.

Add new element to existing JSON array with jq

Here is the test script with 5 steps:

#!/bin/bash

add_element_with_jq() {
    
    # step 1: Add a new root element "{}" first
    echo "============= step 1 ================"
    
    echo "{}" > "package.json"
    
    # step 2: Add a "dependencies" sub element to the root element "{}"
    echo "============= step 2 ================"
    # step 3: Add a "foo" package with version "1.1.1" to the "dependencies"
    echo "============= step 3 ================"
    
    jq '. += dependencies {
      "foo": "1.1.1"
    }' "package.json"
    
    echo "=========== step 3 output =================="
    cat "package.json"
    
    # step 4: Add a "bar" package with version "2.2.2" to the "dependencies"
    echo "============= step 4 ================"
    
    jq '.dependencies += 
      "bar": "2.2.2"
    ' "package.json"
    
    # step 5: If the "foo" package already existed, then update to the latest version. Otherwise, add the "foo" package to the dependencies.
    echo "============= step 5 ================"
    
    jq '.dependencies += 
      "foo": "3.3.3"
    ' "package.json"
    
    echo "=========== final output =================="
    cat "package.json"
}

add_element_with_jq

Here is the error:

============= step 1 ================
============= step 2 ================
============= step 3 ================
jq: error: syntax error, unexpected '{', expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
. += dependencies {                  
jq: 1 compile error
=========== step 3 output ==================
{}
============= step 4 ================
jq: error: syntax error, unexpected ':', expecting $end (Unix shell quoting issues?) at <top-level>, line 2:
      "bar": "2.2.2"           
jq: 1 compile error
============= step 5 ================
jq: error: syntax error, unexpected ':', expecting $end (Unix shell quoting issues?) at <top-level>, line 2:
      "foo": "3.3.3"           
jq: 1 compile error
=========== final output ==================
{}

Here is the expected output:

=========== step 3 output ==================
{
  "dependencies": {
    "foo": "1.1.1"
  }
}
=========== final output ==================
{
  "dependencies": {
    "foo": "3.3.3",
    "bar": "2.2.2"
  }
}

What's wrong in my bash function, and how to fix the jq commands?

2

There are 2 best solutions below

1
ikegami On BEST ANSWER

First of all, all you need is this:

cat <<'.' >package.json
{
   "dependencies": {
      "foo": "3.3.3",
      "bar": "2.2.2"
   }
}
.

But let's assume you have a reason to break it down into steps.


The linked answer is about adding to an array. You are not trying to add to an array. To add a key and value to an object, you can simply use

.object["key"] = value

Therefore, doing one addition at a time, the program would look like the following:

{ } |
.dependencies = { } |
.dependencies[ "foo" ] = "3.3.3" |
.dependencies[ "bar" ] = "2.2.2"

Demo on jqplay.

As separate calls to jq, we get the following:

printf '{ }\n' |
jq '.dependencies = { }' |
jq '.dependencies[ "foo" ] = "3.3.3"' |
jq '.dependencies[ "bar" ] = "2.2.2"' >package.json

As a single pipeline, these commands are still entangled. To separate them, we will need a temporary file or the sponge command-line utility.

printf '{ }\n'                                          >package.tmp1.json
jq '.dependencies = { }'              package.tmp1.json >package.tmp2.json
jq '.dependencies[ "foo" ] = "3.3.3"' package.tmp2.json >package.tmp3.json
jq '.dependencies[ "bar" ] = "2.2.2"' package.tmp3.json >package.tmp4.json

mv package.tmp4.json package.json
rm package.tmp{1,2,3}.json

What if you wanted to add .dependencies only if it didn't already exist? Replace

.dependencies = { }

with

.dependencies //= { }
1
Codebling On

The syntax being used (. += dependencies) seems incorrect.

To add or modify a key in dependencies, use the following syntax:

jq '.dependencies["foo"]="1.1.1"' "package.json"

This will output the edited contents. Since we cannot pipe back into the file (it is open for reading while jq is being executed), we have to pipe it to a new file and rename it (use the mv command for this).

jq '.dependencies["foo"]="1.1.1"' "package.json" > package.json.new \
&& mv package.json.new package.json