Format Package
package.json
files are notorious for becoming large and overwhelming. When working in teams, this can make it hard to know how to structure the file or where to find certain configurations or scripts - especially since everyone has their own preferences.
And manually going through and organizing the file seems as painful as doing formatting checks by hand in PRs.
format-package
solves these problems by allowing the file to be sorted and formatted in a consistent and automated manner.
It is configurable to allow teams to pick the order that work best for them, and includes transformations
that can be applied to a value in the package.json
(such as logically sorting scripts).
Requirements
Getting started
Install
yarn install -D format-package
Command Line
This module provides a simple CLI:
./node_modules/.bin/format-package --help
If combined with Yarn, it can be run as:
yarn format-package --help
It can also be used as part of an npm script:
{
"scripts": {
"format:pkg": "format-package -w"
},
"devDependencies": {
"format-package": "latest"
}
}
yarn format:pkg
Module
The module exports a default format
function that takes the contents of package.json
and a map of options.
It returns a formatted string with a few additional helper functions - toJSON
and toObject
.
const format = require('format-package');
const pkg = require('<path-to-package.json>');
const options = {};
const formattedPkg = format(pkg, options);
From there, it is easy to write the new formatted package back to package.json
:
const fs = require('fs');
fs.writeFile('<path-to-package.json>', formattedPkg, err => {
if (err) throw err;
});
Options
There are three options:
- order (Array)
- transformations (Object)
- formatter (Function)
Options are expected to be passed in as a map:
const format = require('format-package');
const pkg = require('<path-to-package.json>');
const options = { order: [], transformations: {} };
console.log(format(pkg, options).toJSON())
Defaults
The format-package
module also exports its defaults to help with configuration:
const format = require('format-package');
const pkg = require('<path-to-package.json>');
const { { defaults: { order: defaultOrder } } = format;
const restIndex = defaultOrder.indexOf(sort, '...rest');
let order = [...defaultOrder];
if (restIndex !=== -1) order.splice(restIndex, 1);
order.push('...rest');
console.log(format(pkg, { order }).toJSON())
order
The most meaningful part of this utility is an ordered array of keys that are used to order the contents of package.json
.
The default order is:
[
"name",
"version",
"description",
"license",
"private",
"engines",
"repository",
"bugs",
"homepage",
"author",
"bin",
"main",
"module",
"browser",
"config",
"scripts",
"lint-staged",
"...rest",
"dependencies",
"peerDependencies",
"devDependencies",
"optionalDependencies"
]
The ...rest
value is considered special. It marks the location where the remaining package.json
keys that are not found in this ordered list will be placed in alphabetical order.
Note: if a ...rest
string is not found in the provided order list, it will be appended to the bottom.
const format = require('format-package');
const pkg = require('<path-to-package.json>');
const options = {
order: [
'name',
'version',
'scripts',
'jest',
'dependencies',
'peerDependencies',
'devDependencies',
'optionalDependencies',
'...rest',
],
};
const formattedPkg = format(pkg, options);
console.log(formattedPkg.map(([k]) => k));
transformations
transformations
is a map of package.json
keys to functions that return a key and value to be written to package.json
.
The default transformations map has a scripts
method that sorts the scripts in a sensical way using 'sort-scripts'.
const sortScripts = require('sort-scripts');
const transformations = {
scripts(key, prevValue) {
const nextValue = sortScripts(prevValue).reduce(
(obj, [name, value]) => Object.assign({}, obj, { [name]: value }),
{}
);
return [key, nextValue];
},
};
module.exports = transformations;
Notes: Any package.json
property that is an object and does not have a defined transformation will be alphabetically sorted.
Additional transformations or overrides can be passed in:
const format = require('format-package');
const pkg = require('<path-to-package.json>');
const options = {
transformations: {
dependencies(key, value) {
return Object.keys(value)
.sort()
.reverse()
.reduce((obj, k) => {
obj[k] = value[k];
return obj;
}, {});
},
},
};
const formattedPkg = format(pkg, options);
formatter
A custom formatter can be supplied that will process the resulting object before writing to file.
By default, JSON.stringify
is used:
function formatter(obj) {
return JSON.stringify(obj, null, 2);
}
module.exports = formatter;
An alternative would be to use prettier
:
const formatPkg = require('format-package');
const prettier = require('prettier');
const pkg = require('./package.json');
prettier.resolveConfig('./package.json').then(options => {
formatPkg(pkg, { formatter: content => prettier.format(content, options) });
});
CLI
Option | Description | Default |
---|
-c | Path to a custom configuration to use. This configuration can be JavaScript, JSON , or any other format that your configuration of node can require . The default configuration can be found here. | |
-w | Write the output to the location of the found package.json | false |
-v | Print the output of the formatting | false |
-h | Print help menu | |
You can also see the available options in the terminal by running:
yarn format-package --help
Integrating
An effective integration of this plugin could look like this:
{
"scripts": {
"format:pkg": "format-package -w",
"precommit": "lint-staged",
"prepublish": "format:pkg"
},
"lint-staged": {
"package.json": [
"format-package -w -q",
"git add"
]
},
"devDependencies": {
"lint-staged": "latest",
"format-package": "latest"
},
"optionalDependencies": {
"husky": "latest"
}
}
This configuration combines:
Together, these modules ensure the package.json
file is automatically formatted if it changes and provides an easy package.json script for manual use:
yarn format:pkg