Programmatically Edit Any File in NodeJS

September 9th, 2018

NodeJS is useful for way more than just installing packages or running servers. For instance, using the npx package and Node’s filesystem methods, you can create complex logic for interacting with files as if they were plain-ol’ Javascript objects. No BASH required.

This little piece documents a way to programmatically modify package.json. In this example I append JSON output to my existing test script and add a new script into package.json Using this pattern and these methods, you can do basically anything you want inside your repo.

Install NPX

npm i -g npx

Create a File for your NPX Script

touch fs-demo.js

Load package.json as an object

const fs = require('fs');
const pkgJson = require('./package.json’);

CRUD your key/value pairs like any object

const { test: testScript } = packageJson.scripts;

if(testScript.includes('--outputFile')){
  console.log('No changes needed in test script')
} else{
  packageJson.scripts.test = testScript + ' --json --outputFile=jest-test-results.json';
  console.log('Updating test script');
}

packageJson.scripts.foo = 'bar';

Write the updated ‘package.json’ to fs

fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
console.log('Package saved');

NOTE: the additional arguments to JSON.stringify() are there to pretty-print the result. Otherwise you’ll wind up with an unreadable JSON string for the next engineer to prettify. Please practice good coding etiquette ;)

Finally: Run the NPX Script

npx ./fs-demo.js

Here’s the Whole Shebang

const fs = require('fs');
const packageJson = require('./package.json');

const { test: testScript } = packageJson.scripts;

if(testScript.includes('--outputFile')){
  console.log('No changes needed in test script')
} else{
  packageJson.scripts.test = testScript + ' --json --outputFile=jest-test-results.json';
  console.log('Updating test script');
}

packageJson.scripts.foo = 'bar';

fs.writeFileSync('package.json', JSON.stringify(packageJson, null, 2));
console.log('Package saved');

Gotcha: Working with Arbitrary File Types

Working with other file types (say, .gitignore) can be a problem because require doesn’t know what to do with them. It only thinks in terms of Javascript.

To get around this, you can fs.read files into memory and interact with them like strings:

const gitIgnore = fs.readFileSync('./.gitignore', 'utf-8');

You can then chop up your string however you want. For instance in the example below, you can split it on the new-line.

let myGitIgnore = gitIgnore.split(/\n/);

At this point all you’re doing is transforming string data. When you’re done, you reassemble it like above and simply fs.write back to your target file.