Thank you for your interest in contributing to the @nodejs/doc-kit project! We welcome contributions from everyone, and we appreciate your help in making this project better.
- Getting Started
- Development Workflow
- Writing Tests
- Code Quality
- Releasing
- Commit Guidelines
- Developer's Certificate of Origin 1.1
The steps below will give you a general idea of how to prepare your local environment for the @nodejs/doc-kit project and general steps for getting things done and landing your contribution.
- Node.js (latest LTS version, check the
.nvmrcfile) - Git
- A GitHub account
-
Fork the repository
Click the fork button in the top right, or the link in this paragraph, to clone the Node.js
doc-kitRepository -
Clone your fork
git clone git@github.com:<YOUR_GITHUB_USERNAME>/doc-kit.git # SSH git clone https://github.com/<YOUR_GITHUB_USERNAME>/doc-kit.git # HTTPS gh repo clone <YOUR_GITHUB_USERNAME>/doc-kit # GitHub CLI
-
Navigate to the project directory
cd doc-kit -
Set up upstream remote
git remote add upstream git@github.com:nodejs/doc-kit # SSH git remote add upstream https://github.com/nodejs/doc-kit # HTTPS gh repo sync nodejs/doc-kit # GitHub CLI
-
Install dependencies
npm install
This repository is an npm workspaces monorepo. The root package is private and
holds the shared tooling (linting, formatting, tests, changesets); every
published package lives under packages/:
packages/core:@nodejs/doc-kit— the doc-kit engine and CLIpackages/legacy:@nodejs/doc-kit-generator-legacy— the legacy-format generatorspackages/node:@node-core/doc-kit— the Node.js-specific generatorspackages/react:@nodejs/doc-kit-generator-react— the React/JSX-based generators
Everything else at the root supports the repo rather than shipping to npm:
docs/ (the reference docs), www/ (the documentation site), scripts/ (build
and comparison helpers), and e2e/ (Playwright tests).
doc-kit generates documentation from the Markdown API docs in the Node.js repository. To run the tool locally, you need a copy of those source files.
-
Get the Node.js API docs (sparse checkout)
You only need a few directories from the Node.js repo. A sparse checkout avoids downloading the entire repository:
git clone --depth 1 --sparse https://github.com/nodejs/node.git ../node cd ../node git sparse-checkout set doc/api lib CHANGELOG.md cd ../doc-kit
-
Run the tool against a single file
For fast iteration during development, target a single Markdown file instead of all API docs:
node packages/core/bin/cli.mjs generate \ -t legacy-html \ -i ../node/doc/api/fs.md \ -o out \ --index ../node/doc/api/index.md \ -c ../node/CHANGELOG.md
The three flags
-i(input),-t(target generator), and-o(output directory) are effectively required. Without them the tool either crashes or silently does nothing. -
View the generated output
npx serve out
-
Use debug logging
Add
--log-level debugbefore thegeneratesubcommand to see the full pipeline trace:node packages/core/bin/cli.mjs --log-level debug generate -t legacy-html -i ../node/doc/api/fs.md -o out
Tip
See the README for the full list of available generators and CLI options.
-
Create a new branch for your work
git checkout -b <name-of-your-branch>
-
Perform your changes
Make your code changes, add features, fix bugs, or improve documentation.
-
Keep your branch up-to-date
git fetch upstream git merge upstream/main
-
Test your changes
node --run test node --run test:coverage # To check code coverage
-
Check code quality
node --run format:check node --run lint
This project uses Changesets to manage versioning, the changelog, and npm releases. Any change
that affects published behaviour should include a changeset so it shows up in CHANGELOG.md and
triggers a release.
-
Create a changeset
node --run changeset
You'll be prompted for the bump type and a short summary:
- patch — bug fixes and other backwards-compatible changes
- minor — new, backwards-compatible features
- major — breaking changes
The summary becomes the changelog entry, so write it for users of the package.
-
Commit the generated file
This writes a Markdown file under
.changeset/. Commit it alongside your code changes so it lands with your Pull Request.
Note
Changes that don't affect the published package (e.g. tests, CI, or internal docs) don't need a changeset. See Releasing for what happens to changesets after they're merged.
-
Add and commit your changes
git add . git commit -m "describe your changes"
-
Push to your fork
git push -u origin <name-of-your-branch>
-
Create a Pull Request
Go to your fork on GitHub and create a Pull Request to the main repository.
Important
Before committing and opening a Pull Request, please go through our Commit Guidelines and ensure your code passes all tests and quality checks.
Testing is a crucial part of maintaining code quality and ensuring reliability. All contributions should include appropriate tests.
- Patches (PRs) are required to maintain 80% coverage minimum
- Contributors are encouraged to strive for 95-100% coverage
- New features and bug fixes should include corresponding tests
- Tests should cover both happy path and edge cases
Tests should be organized to mirror the source code structure. The paths below
are relative to the package the source file lives in (e.g. packages/core):
-
For a source file at
/src/index.mjs, create a test file at/src/__tests__/index.test.mjs -
For a source file at
/src/utils/parser.mjs, create a test file at/src/utils/__tests__/parser.test.mjs -
Test files should use the
.test.mjsextension -
For a fixture used in
/src/__tests__/some.test.mjs, place the fixture at/src/__tests__/fixtures/some-fixture.mjs. -
When fixtures are used in multiple tests, place them in the test directory of the closest shared ancestor. For instance, if a fixture is used by both
/src/__tests__/some.test.mjs, and/src/utils/__tests__/parser.test.mjs, the fixture belongs in/src/__tests__/fixtures/.
Tests should follow these guidelines:
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';Use describe and it syntax for organizing tests:
describe('MyModule', () => {
describe('myFunction', () => {
it('should return expected result for valid input', () => {
// Test implementation
assert.strictEqual(actual, expected);
});
it('should throw error for invalid input', () => {
assert.throws(() => {
// Code that should throw
});
});
});
});- Use strict assertions: Always use
node:assert/strictovernode:assert. - Focused testing: Tests should ideally only test the specific file they are intended for
- Use mocking: Mock external dependencies to isolate the code under test
- Code splitting: Encourage breaking down complex functionality for easier testing
// tests/index.test.mjs
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { myFunction } from '../index.mjs';
describe('index.mjs', () => {
describe('myFunction', () => {
it('should process valid input correctly', () => {
const input = 'test input';
const result = myFunction(input);
assert.strictEqual(result, 'expected output');
});
it('should handle edge cases', () => {
assert.strictEqual(myFunction(''), '');
assert.strictEqual(myFunction(null), null);
});
it('should throw for invalid input', () => {
assert.throws(() => myFunction(undefined), {
name: 'TypeError',
message: 'Input cannot be undefined',
});
});
});
});# Run all tests
node --run test
# Run tests with coverage
node --run test:coverage
# Run specific test file
node --test packages/core/src/utils/__tests__/parser.test.mjsThis project uses automated code quality tools:
# Format code
node --run format # To only check formatting, use `format:check`
# Lint code
node --run lint # To apply changes, use `lint:fix`This project uses Husky for Git pre-commit hooks that automatically lint and format your code before committing.
You can bypass pre-commit hooks if necessary (not recommended):
git commit -m "describe your changes" --no-verifyReleases are automated with Changesets and require no manual version bumps — maintainers never
edit the version field in package.json by hand.
When changesets land on main, the Publish workflow opens (or
updates) a "Version Packages" Pull Request that consumes the pending changeset files, bumps the
version in package.json, and writes the corresponding CHANGELOG.md entries.
To ship a release, a maintainer merges that "Version Packages" PR. The same workflow then:
- publishes the workspace packages to npm (via npm trusted publishing — no token required),
- creates the matching
v<x.y.z>git tag, and - cuts a GitHub Release from the changelog.
This project follows the Conventional Commits specification.
By contributing to this project, I certify that:
- (a) The contribution was created in whole or in part by me and I have the right to
submit it under the open source license indicated in the file; or
- (b) The contribution is based upon previous work that, to the best of my knowledge,
is covered under an appropriate open source license and I have the right under that
license to submit that work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am permitted to submit under a
different license), as indicated in the file; or
- (c) The contribution was provided directly to me by some other person who certified
(a), (b) or (c) and I have not modified it.
- (d) I understand and agree that this project and the contribution are public and that
a record of the contribution (including all personal information I submit with it,
including my sign-off) is maintained indefinitely and may be redistributed consistent
with this project or the open source license(s) involved.