Reputation: 13119
I've got a simple package.json
file and I want to add a comment. Is there a way to do this, or are there any hacks to make this work?
{
"name": "My Project",
"version": "0.0.1",
"private": true,
"dependencies": {
"express": "3.x",
"mongoose": "3.x"
},
"devDependencies" : {
"should": "*"
/* "mocha": "*" not needed as should be globally installed */
}
}
The example comment above doesn't work as npm breaks. I've also tried //
style comments.
Upvotes: 626
Views: 257817
Reputation: 43547
Most of my json commenting needs actually come in a pretty specific place, that is, in the scripts part of the package.json file in node projects.
Since the root-level "//"
key only works at the root level it's quite awkward to talk about individual items in scripts from "far away".
I found a tip for making a bash comment, which is to have a command like : 'Comment contents'
. This is resilient to multiline as well but importantly for this use case it allows us to insert a no-op command in the middle of other commands that works like a comment. The syntax terseness is icing on the cake, though it is slightly cryptic, the colon command being a no-op is easy to learn.
Example package.json
:
{
...
"scripts": {
"build": "node ./scripts/build.js",
"test": "vitest",
"custom-test": ":'Custom basic test suite for tooling'; node ./build/test/customtest.js"
}
...
}
Upvotes: 0
Reputation: 1055
I add a help
script:
"scripts" {
"help": "cat ./help.md"
}
Upvotes: 2
Reputation: 1274
So far, most "hacks" here suggest to abuse JSON. But instead, why not abuse the underlying scripting language?
Edit The initial response was putting the description on the right using # add comments here
to wrap it; however, this does not work on Windows, because flags (e.g., npm run myframework -- --myframework-flags
) would be ignored. I changed my response to make it work on all platforms, and added some indents for readability purposes.
{
"scripts": {
"help": " echo 'Display help information (this screen)'; npm run",
"myframework": "echo 'Run myframework binary'; myframework",
"develop": " echo 'Run in development mode (with terminal output)'; npm run myframework"
"start": " echo 'Start myFramework as a daemon'; myframework start",
"stop": " echo 'Stop the myFramework daemon'; myframework stop"
"test": "echo \"Error: no test specified\" && exit 1"
}
}
This will:
npm run myframework -- --help
npm run
(which is the actual command to run to get information about available scripts)package.json
(using less
or your favorite IDE)Upvotes: 11
Reputation: 25172
Inspired by this thread, here's what we are using:
{
"//dependencies": {
"crypto-exchange": "Unified exchange API"
},
"dependencies": {
"crypto-exchange": "^2.3.3"
},
"//devDependencies": {
"chai": "Assertions",
"mocha": "Unit testing framwork",
"sinon": "Spies, Stubs, Mocks",
"supertest": "Test requests"
},
"devDependencies": {
"chai": "^4.1.2",
"mocha": "^4.0.1",
"sinon": "^4.1.3",
"supertest": "^3.0.0"
}
}
Upvotes: 33
Reputation: 1637
I've been doing this:
{
...
"scripts": {
"about": "echo 'Say something about this project'",
"about:clean": "echo 'Say something about the clean script'",
"clean": "do something",
"about:build": "echo 'Say something about building it'",
"build": "do something",
"about:watch": "echo 'Say something about how watch works'",
"watch": "do something",
}
...
}
This way, I can both read the "pseudo-comments" in the script itself, and also run something like the following, to see some kind of help in the terminal:
npm run about
npm run about:watch
Even better if you are using yarn
.
yarn about:clean
Also, as pointed out by @Dakota Jang in comments, you can use keys like //something
to make it even more clear that this is a comment.
Like so:
{
...
"scripts": {
"//clean": "echo 'Say something about the clean script'",
"clean": "do something",
"//build": "echo 'Say something about building it'",
"build": "do something",
"//watch": "echo 'Say something about how watch works'",
"watch": "do something",
}
...
}
And then run:
npm run //build
# or
yarn //build
And you will have a helper output in your terminal, and a "comment" in your package.json as well.
Upvotes: 90
Reputation: 847
I have a funny hack idea.
Create an npm package name suitably as a comment divider for dependencies
and devDependencies
block in file package.json, for example x----x----x
{
"name": "app-name",
"dependencies": {
"x----x----x": "this is the first line of a comment",
"babel-cli": "6.x.x",
"babel-core": "6.x.x",
"x----x----x": "this is the second line of a comment",
"knex": "^0.11.1",
"mocha": "1.20.1",
"x----x----x": "*"
}
}
NOTE: You must add the last comment divider line with a valid version, like *
in the block.
Upvotes: 11
Reputation: 2648
NPS (Node Package Scripts) solved this problem for me. It lets you put your NPM scripts into a separate JavaScript file, where you can add comments galore and any other JavaScript logic you need to. https://www.npmjs.com/package/nps
Sample of the package-scripts.js
from one of my projects:
module.exports = {
scripts: {
// makes sure e2e webdrivers are up to date
postinstall: 'nps webdriver-update',
// run the webpack dev server and open it in browser on port 7000
server: 'webpack-dev-server --inline --progress --port 7000 --open',
// start webpack dev server with full reload on each change
default: 'nps server',
// start webpack dev server with hot module replacement
hmr: 'nps server -- --hot',
// generates icon font via a gulp task
iconFont: 'gulp default --gulpfile src/deps/build-scripts/gulp-icon-font.js',
// No longer used
// copyFonts: 'copyfiles -f src/app/glb/font/webfonts/**/* dist/1-0-0/font'
}
}
I just did a local install npm install nps -save-dev
and put this in my package.json
scripts.
"scripts": {
"start": "nps",
"test": "nps test"
}
Upvotes: 33
Reputation: 44009
You can always abuse the fact that duplicated keys are overwritten. This is what I just wrote:
"dependencies": {
"grunt": "...",
"grunt-cli": "...",
"api-easy": "# Here is the pull request: https://github.com/...",
"api-easy": "git://..."
"grunt-vows": "...",
"vows": "..."
}
However, it is not clear whether JSON allows duplicated keys (see Does JSON syntax allow duplicate keys in an object?. It seems to work with npm, so I take the risk.
The recommened hack is to use "//"
keys (from the nodejs mailing list). When I tested it, it did not work with "dependencies" sections, though. Also, the example in the post uses multiple "//"
keys, which implies that npm does not reject JSON files with duplicated keys. In other words, the hack above should always be fine.
Update: One annoying disadvantage of the duplicated key hack is that npm install --save
silently eliminates all duplicates. Unfortunately, it is very easy to overlook it and your well-intentioned comments are gone.
The "//"
hack is still the safest as it seems. However, multi-line comments will be removed by npm install --save
, too.
Upvotes: 16
Reputation: 2502
DISCLAIMER: you probably should not use this hack. See comments below.
Here is another hack for adding comments in JSON
. Since:
{"a": 1, "a": 2}
Is equivalent to:
{"a": 2}
You can do something like:
{
"devDependencies": "'mocha' is not needed as it should be globally installed",
"devDependencies" : {
"should": "*"
}
}
Upvotes: 129
Reputation: 4294
After wasting an hour on complex and hacky solutions, I've found both simple and valid solution for commenting my bulky dependencies section in package.json
. Just like this:
{
"name": "package name",
"version": "1.0",
"description": "package description",
"scripts": {
"start": "npm install && node server.js"
},
"scriptsComments": {
"start": "Runs development build on a local server configured by server.js"
},
"dependencies": {
"ajv": "^5.2.2"
},
"dependenciesComments": {
"ajv": "JSON-Schema Validator for validation of API data"
}
}
When sorted the same way, it's now very easy for me to track these pairs of dependencies/comments either in Git commit diffs or in an editor while working with file package.json
.
And no extra tools are involved, just plain and valid JSON.
Upvotes: 308
Reputation: 170
Here is another take on that matter - for commenting scripts in npm.
Consider that scripts are arguments to 'npm run'. So what is the standard way of getting description of some commands passed through arguments?
One is usually typing executable command --help
to get help on a command, another common pattern is executable help command
.
Following the second pattern you can have following code in your npm scripts:
"scripts": {
"help": "node -e \"const {spawn} = require('child_process');spawn('npm', ['run','help '+process.argv[1]],{stdio:'inherit'})\"",
"help some-command":"echo 'some-command executes a command sequence, the command line is: npm run some-command [--some-switch] [--some-parameter=value] '"
"some-command":"execute; command; sequence",
}
Now you can run intuitive command npm run help some-command
and it will run the script "help some-command".
The "help" script is for convenience as it's only purpose is to not be forced to type unintuitive npm run "help some-command"
with quotes in order to run the "help some-command" script.
Upvotes: 0
Reputation: 742
Since most developers are familiar with tag/annotation-based documentation, the convention I have been using is similar. I like how the @
symbol stands out from the normal declarations.
Here is a taste:
{
"@comment dependencies": {
"@comment": [
"These are the general/global comments for the `dependencies` section.",
"They are not specific to a particular package.",
"See below for how to add comments specific to a package.",
],
"@package express": [
"Use `@package {package-name}` to make comments specific to a package.",
"",
"This is a good place to explain why the version range isn't ",
"`^version` or why the latest major version isn't being used, ",
"e.g., ESM is not supported in the project at the moment."
],
"@package lodash": [
"Until we add a tool to tree shake unused parts of a lodash, ",
"only depend on the [per method packages](https://www.npmjs.com/search?q=keywords:lodash-modularized) ",
"such as `lodash.debounce`."
]
},
"dependencies": {
...
},
"@comment scripts": {
"@comment Use with NPM": [
"Be sure to add ` -- ` before adding options.",
"For example, `npm run build -- --opt1 val1`."
],
"@comment Use with Yarn": "...",
"@script build": "This comment is about the build script.",
"@script start": [
"This comment is about the `start` script.",
"It is wrapped in an array to allow line formatting.",
"",
"@option {number} --port - The port the server should listen on."
],
"@script test": "This comment is about the test script.",
},
"scripts": {
"build": "...",
"start": "...",
"test": "..."
}
}
Note: The name of the section being commented is included in the key after the @comment {section-name}
to ensure the keys are unique. That is, using just "@comment" would not be sufficient to keep keys unique if you need to add another comment at the same level. If the keys weren't unique, JSON validators, such as ones built into IDEs, will complain, or some tools, such as running npm install something
, will rewrite the package.json
file but with duplicate keys removed.
Because JSON doesn't allow a multi-line string or understand a line continuation operator/character, just use an array for each line of the comment.
It is recommended to use Markdown or something similar to help clarify your comments.
Note: For the dependencies
, devDependencies
, etc. sections, the comment annotations can't be added directly above the individual package dependencies inside the configuration object since npm
is expecting the key to be the name of an npm package. Hence the reason for the @comment dependencies
.
Note: For the dependencies
, devDependencies
, scripts
, etc. sections, the embedded @comment
keys may or may not contain a section name.
Older dependencies
Recommendation
The following was my previous recommendation for the various dependency sections (dependencies
, devDependencies
, etc).
{
"@comment dependencies": [
"These are the comments for the `dependencies` section.",
"The name of the section being commented is included in the key after the `@comment` 'annotation'/'tag' to ensure the keys are unique.",
"That is, using just \"@comment\" would not be sufficient to keep keys unique if you need to add another comment at the same level.",
"Because JSON doesn't allow a multi-line string or understand a line continuation operator/character, just use an array for each line of the comment.",
"Since this is embedded in JSON, the keys should be unique.",
"Otherwise JSON validators, such as ones built into IDEs, will complain.",
"Or some tools, such as running `npm install something --save`, will rewrite the `package.json` file but with duplicate keys removed.",
"",
"@package react - Using an `@package` 'annotation` could be how you add comments specific to particular packages."
],
"dependencies": {
...
},
"scripts": {
...
},
Older scripts
Recommendation
The following was my previous recommendation. It in-lined comments for the scripts, but I've come to realize that those comments show up as "commands" in some tools (in VS Code > Explorer > NPM Scripts section). The latest recommendation does not suffer from this issue but the script comments are no longer co-located.
{
"@comment dependencies": [
...
],
"dependencies": {
...
},
"scripts": {
"@comment build": "This comment is about the build script.",
"build": "...",
"@comment start": [
"This comment is about the `start` script.",
"It is wrapped in an array to allow line formatting.",
"When using npm, as opposed to yarn, to run the script, be sure to add ` -- ` before adding the options.",
"",
"@option {number} --port - The port the server should listen on."
],
"start": "...",
"@comment test": "This comment is about the test script.",
"test": "..."
}
}
Note: In certain contexts, such as in the "scripts"
object, some editors/IDEs may complain about the array. In the scripts context, VS Code expects a string for the value — not an array.
Upvotes: 24
Reputation: 6822
This has recently been discussed on the Node.js mailing list.
According to Isaac Schlueter who created npm:
... the "//" key will never be used by npm for any purpose, and is reserved for comments ... If you want to use a multiple line comment, you can use either an array, or multiple "//" keys.
When using your usual tools (npm, yarn, etc.), multiple "//"
keys will be removed. This survives:
{ "//": [
"first line",
"second line" ] }
This will not survive:
{ "//": "this is the first line of a comment",
"//": "this is the second line of the comment" }
One must be aware that
"//"
can only be used at the root of thepackage.json
object. For example{ "//": "comment!", "dependencies": {...} }
is valid but
{ "dependencies": { "//": "comment?" } }
is invalid.
Upvotes: 636
Reputation: 601
As of pnpm 7.17.1, which was just released, you can switch to pnpm for package management, move your package.json to package.json5, and comments in package.json5 are allowed and will be preserved by pnpm. Note however that for publishing as a package to use on the npm registry (for example), a package.json5 will not be recognized by other package managers and I doubt by all of the registry's processing. So you would have to convert the package.json5 to a package.json before publishing. On the other hand, for "top-level applications" that are unlikely to be included as packages in other projects, a package.json5 seems to work just fine, as long as you then stick with pnpm as your package manager.
Upvotes: 4
Reputation: 14936
Commands in "scripts" are bash code - and we can comment bash:
"dedup": "yarn-deduplicate && yarn # TODO remove this on yarn/npm v2 because integrated"
Bonus: when you run it - you will see the comment too:
Upvotes: 1
Reputation: 121
In addition to the global // comment (or array of comments), you can use the semver pipe separator for comments on particular dependencies, e.g.
"@types/node": "^16.11.7 || keep-same-major-version-as-node"
Upvotes: -1
Reputation:
I do something that's some of you might like:
This // inside of the name means it's a comment for me:
"//":"Main and typings are used till ES5",
"//main": "build/index",
"//typings": "build/index",
Upvotes: 1
Reputation: 189
I like this:
"scripts": {
"⏬⏬⏬ Jenkins Build - in this order ⏬⏬⏬ ": "",
"purge": "lerna run something",
"clean:test": "lerna exec --ignore nanana"
}
There are extra spaces in the command name, so in Visual Studio Code's NPM Scripts plugin you have a better look.
Upvotes: 0
Reputation: 97048
To summarise all of these answers:
Add a single top-level field called //
that contains a comment string. This works, but it sucks because you can't put comments near the thing they are commenting on.
Add multiple top-level fields starting with //
, e.g. //dependencies
that contains a comment string. This is better, but it still only allows you to make top-level comments. You can't comment individual dependencies.
Add echo
commands to your scripts
. This works, but it sucks because you can only use it in scripts
.
These solutions are also all not very readable. They add a ton of visual noise and IDEs will not syntax highlight them as comments.
I think the only reasonable solution is to generate the package.json
from another file. The simplest way is to write your JSON as JavaScript and use Node.js to write it to package.json
. Save this file as package.json.mjs
, chmod +x
it, and then you can just run it to generate your package.json
.
#!/usr/bin/env node
import { writeFileSync } from "fs";
const config = {
// TODO: Think of better name.
name: "foo",
dependencies: {
// Bar 2.0 does not work due to bug 12345.
bar: "^1.2.0",
},
// Look at these beautify comments. Perfectly syntax highlighted, you
// can put them anywhere and there no risk of some tool removing them.
};
writeFileSync("package.json", JSON.stringify({
"//": "This file is \x40generated from package.json.mjs; do not edit.",
...config
}, null, 2));
It uses the //
key to warn people from editing it. \x40generated
is deliberate. It turns into @generated
in package.json
and means some code review systems will collapse that file by default.
It's an extra step in your build system, but it beats all of the other hacks here.
Upvotes: 8
Reputation: 29
For npm's package.json, I have found two ways (after reading this conversation):
"devDependencies": {
"del-comment": [
"some-text"
],
"del": "^5.1.0 ! inner comment",
"envify-comment": [
"some-text"
],
"envify": "4.1.0 ! inner comment"
}
But with the update or reinstall of package with "--save" or "--save-dev, a comment like "^4.1.0 ! comment" in the corresponding place will be deleted. And all this will break npm audit.
Upvotes: 0
Reputation: 925
I created a script to read file package.json as the context for a handlebars template.
The code is below, in case someone finds this approach useful:
const templateData = require('../package.json');
const Handlebars = require('handlebars');
const fs = require('fs-extra');
const outputPath = __dirname + '/../package-json-comments.md';
const srcTemplatePath = __dirname + '/package-json-comments/package-json-comments.hbs';
Handlebars.registerHelper('objlist', function() {
// The first argument is an object, and the list is a set of keys for that obj
const obj = arguments[0];
const list = Array.prototype.slice.call(arguments, 1).slice(0,-1);
const mdList = list.map(function(k) {
return '* ' + k + ': ' + obj[k];
});
return new Handlebars.SafeString(mdList.join("\n"));
});
fs.readFile(srcTemplatePath, 'utf8', function(err, srcTemplate){
if (err) throw err;
const template = Handlebars.compile(srcTemplate);
const content = template(templateData);
fs.writeFile(outputPath, content, function(err) {
if (err) throw err;
});
});
handlebars template file package-json-comments.hbs
### Dependency Comments
For package: {{ name }}: {{version}}
#### Current Core Packages
should be safe to update
{{{objlist dependencies
"@material-ui/core"
"@material-ui/icons"
"@material-ui/styles"
}}}
#### Lagging Core Packages
breaks current code if updated
{{{objlist dependencies
"amazon-cognito-identity-js"
}}}
#### Major version change
Not tested yet
{{{objlist dependencies
"react-dev-utils"
"react-redux"
"react-router"
"redux-localstorage-simple"
}}}
Upvotes: 0
Reputation: 223094
As this answer explains, the //
key was reserved, so it can be used conventionally for comments. The problem with //
comment is that it's not practical, because it can't be used multiple times. Duplicate keys are deleted on package.json automatic updates:
"//": "this comment about dependencies stays",
"dependencies": {}
"//": "this comment disappears",
"devDependencies": {}
Another problem is that //
comment can't be used inside dependencies
and devDependencies
because it's treated as a regular dependency:
"dependencies": {
"//": "comment"
}
npm ERR! code EINVALIDPACKAGENAME
npm ERR! Invalid package name "//": name can only contain URL-friendly characters
A workaround that works in NPM, but not Yarn, is to use a non-string value:
"dependencies": {
"foo": ["unused package"],
}
A workaround that works in NPM and Yarn is a comment added as a part of semantic versioning:
"dependencies": {
"bar": "^2",
"foo": "^2 || should be removed in 1.x release"
}
Notice that if the first part before OR
doesn't match, versions from a comment can be parsed, e.g. 1.x
.
Packages that need to be commented, but not installed, should be moved to another key, e.g. dependencies //
:
"dependencies //": {
"baz": "unused package",
}
Upvotes: 10
Reputation: 1962
As duplicate comment keys are removed running package.json tools (npm, yarn, etc.), I came to using a hashed version which allows for better reading as multiple lines and keys like:
"//": {
"alpaca": "we use the bootstrap version",
"eonasdan-bootstrap-datetimepicker": "instead of bootstrap-datetimepicker",
"moment-with-locales": "is part of moment"
},
which is 'valid' according to my IDE as a root key, but within dependencies
it complains expecting a string value.
Upvotes: 1
Reputation: 2668
Here's my take on comments within package.json
/ bower.json
:
I have file package.json.js
that contains a script that exports the actual package.json
. Running the script overwrites the old package.json
and tells me what changes it made, perfect to help you keep track of automatic changes npm
made. That way I can even programmatically define what packages I want to use.
The latest Grunt task is here: https://gist.github.com/MarZab/72fa6b85bc9e71de5991
Upvotes: 7
Reputation: 6454
My take on the frustration of no comments in JSON. I create new nodes, named for the nodes they refer to, but prefixed with underscores. This is imperfect, but functional.
{
"name": "myapp",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-scripts": "1.1.4"
},
"scripts": {
"__start": [
"a note about how the start script works"
],
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"__proxy": [
"A note about how proxy works",
"multilines are easy enough to add"
],
"proxy": "http://server.whatever.com:8000"
}
Upvotes: -1
Reputation: 23813
I ended up with a scripts
like that:
"scripts": {
"//-1a": "---------------------------------------------------------------",
"//-1b": "---------------------- from node_modules ----------------------",
"//-1c": "---------------------------------------------------------------",
"ng": "ng",
"prettier": "prettier",
"tslint": "tslint",
"//-2a": "---------------------------------------------------------------",
"//-2b": "--------------------------- backend ---------------------------",
"//-2c": "---------------------------------------------------------------",
"back:start": "node backend/index.js",
"back:start:watch": "nodemon",
"back:build:prod": "tsc -p backend/tsconfig.json",
"back:serve:prod": "NODE_ENV=production node backend/dist/main.js",
"back:lint:check": "tslint -c ./backend/tslint.json './backend/src/**/*.ts'",
"back:lint:fix": "yarn run back:lint:check --fix",
"back:check": "yarn run back:lint:check && yarn run back:prettier:check",
"back:check:fix": "yarn run back:lint:fix; yarn run back:prettier:fix",
"back:prettier:base-files": "yarn run prettier './backend/**/*.ts'",
"back:prettier:fix": "yarn run back:prettier:base-files --write",
"back:prettier:check": "yarn run back:prettier:base-files -l",
"back:test": "ts-node --project backend/tsconfig.json node_modules/jasmine/bin/jasmine ./backend/**/*spec.ts",
"back:test:watch": "watch 'yarn run back:test' backend",
"back:test:coverage": "echo TODO",
"//-3a": "---------------------------------------------------------------",
"//-3b": "-------------------------- frontend ---------------------------",
"//-3c": "---------------------------------------------------------------",
"front:start": "yarn run ng serve",
"front:test": "yarn run ng test",
"front:test:ci": "yarn run front:test --single-run --progress=false",
"front:e2e": "yarn run ng e2e",
"front:e2e:ci": "yarn run ng e2e --prod --progress=false",
"front:build:prod": "yarn run ng build --prod --e=prod --no-sourcemap --build-optimizer",
"front:lint:check": "yarn run ng lint --type-check",
"front:lint:fix": "yarn run front:lint:check --fix",
"front:check": "yarn run front:lint:check && yarn run front:prettier:check",
"front:check:fix": "yarn run front:lint:fix; yarn run front:prettier:fix",
"front:prettier:base-files": "yarn run prettier \"./frontend/{e2e,src}/**/*.{scss,ts}\"",
"front:prettier:fix": "yarn run front:prettier:base-files --write",
"front:prettier:check": "yarn run front:prettier:base-files -l",
"front:postbuild": "gulp compress",
"//-4a": "---------------------------------------------------------------",
"//-4b": "--------------------------- cypress ---------------------------",
"//-4c": "---------------------------------------------------------------",
"cy:open": "cypress open",
"cy:headless": "cypress run",
"cy:prettier:base-files": "yarn run prettier \"./cypress/**/*.{js,ts}\"",
"cy:prettier:fix": "yarn run front:prettier:base-files --write",
"cy:prettier:check": "yarn run front:prettier:base-files -l",
"//-5a": "---------------------------------------------------------------",
"//-5b": "--------------------------- common ----------------------------",
"//-5c": "---------------------------------------------------------------",
"all:check": "yarn run back:check && yarn run front:check && yarn run cy:prettier:check",
"all:check:fix": "yarn run back:check:fix && yarn run front:check:fix && yarn run cy:prettier:fix",
"//-6a": "---------------------------------------------------------------",
"//-6b": "--------------------------- hooks -----------------------------",
"//-6c": "---------------------------------------------------------------",
"precommit": "lint-staged",
"prepush": "yarn run back:lint:check && yarn run front:lint:check"
},
My intent here is not to clarify one line, just to have some sort of delimiters between my scripts for backend, frontend, all, etc.
I'm not a huge fan of 1a, 1b, 1c, 2a, ... but the keys are different and I do not have any problem at all like that.
Upvotes: 4