Skip to content

Commit 6e4f221

Browse files
committed
doc: note that message.headers/trailers have a null prototype
1 parent 8c7c040 commit 6e4f221

3 files changed

Lines changed: 176 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Node.js Agent Guide
2+
3+
Non-discoverable conventions, commands, and landmines for the `nodejs/node` repository.
4+
5+
## Scope & routing
6+
7+
This is the Node.js upstream source repository.
8+
9+
| Area | What to read |
10+
|---|---|
11+
| JS runtime code | `lib/` |
12+
| C++ runtime code | `src/` |
13+
| Tests | `test/` (see "Test directories" below) |
14+
| Docs (API YAML + MD) | `doc/api/` |
15+
| Bundled deps | `deps/` — send patches upstream, not here |
16+
| Build / tooling | `tools/`, `Makefile`, `configure` |
17+
18+
## Commands
19+
20+
### Build & test
21+
22+
| Command | What it does |
23+
|---|---|
24+
| `make` | Build a release binary |
25+
| `make -j4` | Parallel build (use `-j` = CPU cores) |
26+
| `make lint` | Run JS, C++, MD, and addon-doc linters |
27+
| `make lint-js` | JS lint only |
28+
| `make lint-cpp` | C++ lint only |
29+
| `make lint-md` | Markdown lint only |
30+
| `make lint-js-fix` | Auto-fix JS lint errors |
31+
| `make test` | Build + run default tests + lint + build docs |
32+
| `make test-only` | Run default tests (skip lint & docs build) |
33+
| `make test-all` | Run tests with both Debug and Release builds |
34+
| `make test-ci` | Full CI build + test (what CI runs) |
35+
| `make build-addons` | Build native addon test binaries |
36+
| `make test-build` | Build all native test addons |
37+
38+
Run a single test:
39+
```bash
40+
./node out/Release/node test/parallel/test-http-server-response-end.js
41+
```
42+
43+
Run a test directory:
44+
```bash
45+
./tools/test.py --mode=release test/parallel/
46+
```
47+
48+
### Debug builds
49+
50+
```bash
51+
make clean
52+
./configure --debug
53+
make -j4
54+
./node out/Debug/node test/parallel/test-foo.js
55+
```
56+
57+
### Docs
58+
59+
```bash
60+
make doc # Build HTML docs
61+
make lint-md # Lint markdown
62+
make lint-addon-docs # Lint addon documentation
63+
```
64+
65+
## Test directories
66+
67+
| Directory | CI | Notes |
68+
|---|---|---|
69+
| `test/parallel/` | Yes | Main test suite; safe to run in parallel |
70+
| `test/sequential/` | Yes | Must run one at a time |
71+
| `test/pummel/` | No | Stress/load tests; flaky |
72+
| `test/internet/` | No | Real outbound network connections |
73+
| `test/addons/` | Yes | Requires `make build-addons` |
74+
| `test/node-api/` | Yes | Requires `make build-node-api-tests` |
75+
| `test/js-native-api/` | Yes | Requires `make build-js-native-api-tests` |
76+
| `test/sqlite/` | Yes | Requires `make build-sqlite-tests` |
77+
| `test/known_issues/` | Yes | All tests expected to fail; skip via `root.status` |
78+
| `test/abort/` | Yes | Uses `--abort-on-uncaught-exception` |
79+
80+
## Test writing rules
81+
82+
These are not discoverable from reading the code:
83+
84+
1. **Always `require('../common')` first**, even if unused. It enables global leak detection.
85+
2. **Use `common.mustCall(callback, n)`** to verify callbacks fire exactly `n` times. This is preferred over manual counters + assertions on exit.
86+
3. **Use `common.mustCallAtLeast(callback, n)`** for "at least" checks.
87+
4. **Use `common.platformTimeout(ms)`** for any timer — it auto-scales on slow platforms (debug, Raspberry Pi, RISC-V).
88+
5. **Use port `0`** instead of hard-coded ports to allow parallel test execution.
89+
6. **Avoid timers unless testing timers** — they are a primary source of flakiness.
90+
7. **New tests go in new files**, not appended to existing files, unless there is strong motivation to share setup.
91+
8. **Start each test with a comment** describing what it tests.
92+
9. **Test files must exit with code 0** on success (graceful exit, not `process.exit()`).
93+
10. **Use `--expose-internals`** via `// Flags: --expose-internals` preamble comment to access `node:internal/*` modules.
94+
11. **Use `node:internal/test/binding`** to access `internalBinding()` and primordials from tests.
95+
12. **Prefer `assert.strictEqual()` / `assert.deepStrictEqual()`** over non-strict variants.
96+
13. **For internal errors, check only the `code` property** (not the message string) in `assert.throws()`.
97+
14. **Use `node:` protocol prefix** for core module imports in tests (`require('node:assert')`).
98+
15. **Use `common.skip(msg)`** to skip tests conditionally — prints TAP skip and exits 0.
99+
16. **ES.Next features in tests**: use features available without flags on all maintained branches (`let`/`const`, template literals, arrow functions). Avoid features requiring flags to aid backporting.
100+
101+
## Code conventions
102+
103+
### JavaScript (`lib/`)
104+
105+
- 2-space indent, single quotes, semicolons (enforced by `make lint-js`).
106+
- Trailing commas in object/array literals.
107+
- `use strict` at top of every file.
108+
- Sort `require` statements in ASCII order.
109+
- Prefer `node:` protocol for core modules.
110+
- Use `const` / `let` — no `var`.
111+
- ES.Next features in `lib/` are limited to a selected subset for performance (see `doc/api/esnext.md`).
112+
113+
### C++ (`src/`)
114+
115+
- Follow the [C++ Style Guide](doc/contributing/cpp-style-guide.md).
116+
- Run `make lint-cpp` to check.
117+
- Read `src/README.md` for internals overview.
118+
119+
### Documentation (`doc/api/`)
120+
121+
- Use `REPLACEME` for version numbers in YAML frontmatter (CI replaces them).
122+
- Code samples in API docs are linted by `make lint`.
123+
- Follow the [Style Guide](doc/README.md).
124+
125+
## Commit messages
126+
127+
Format: `<subsystem>: <imperative description>`
128+
129+
- Subsystem prefix is required — check `git log --oneline <files>` to find the right one.
130+
- First line: all lowercase except proper nouns/identifiers, max ~72 chars.
131+
- Blank second line.
132+
- Wrap body at 72 columns.
133+
- Add `Fixes: <issue URL>` or `Refs: <URL>` trailers.
134+
- Breaking changes need explicit explanation.
135+
136+
## Landmines
137+
138+
- **`deps/`**: Do not send patches for bundled dependencies. Send them to the upstream project.
139+
- **`tools/`**: Contains vendored tooling (eslint, cpplint, etc.) — not Node.js project code.
140+
- **`test/common/`**: Shared test helpers — read `test/common/README.md` for the full API.
141+
- **`test/known_issues/`**: Tests here are *expected to fail*. Skip logic lives in `test/known_issues.status`.
142+
- **`test/pummel/`**: Stress tests not run in CI — flaky by design.
143+
- **`test/internet/`**: Real network calls — not run in CI.
144+
- **Global leak detection**: `test/common` registers an `process.on('exit')` handler that fails on leaked globals. Set `NODE_TEST_KNOWN_GLOBALS` to allow specific globals.
145+
- **`isDebug` affects timeouts**: Use `common.platformTimeout()` — raw `setTimeout` values will fail on debug builds.
146+
- **`node:internal/test/binding`** only works with `--expose-internals` flag.
147+
- **Native addon tests** (`test/addons/`, `test/node-api/`, etc.) require a build step before running.
148+
- **`.editorconfig`** sets 2-space indent, single quotes, LF line endings. `Makefile` uses tabs. `deps/` files are excluded from editorconfig rules.
149+
150+
## What not to put here (discoverable from repo)
151+
152+
- Build prerequisites (in `BUILDING.md`)
153+
- Full pull request workflow (in `doc/contributing/pull-requests.md`)
154+
- Full test writing guide (in `doc/contributing/writing-tests.md`)
155+
- C++ style rules (in `doc/contributing/cpp-style-guide.md`)
156+
- Governance / team structure (in `README.md`, `GOVERNANCE.md`)
157+
- ESLint rules (enforced by `make lint-js`)
158+
- CI configuration (in `.github/workflows/`)

doc/api/http.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,6 +2863,9 @@ The request/response headers object.
28632863

28642864
Key-value pairs of header names and values. Header names are lower-cased.
28652865

2866+
The object has a null prototype and should not be accessed using the `in`
2867+
operator.
2868+
28662869
```js
28672870
// Prints something like:
28682871
//
@@ -2900,6 +2903,9 @@ added:
29002903
Similar to [`message.headers`][], but there is no join logic and the values are
29012904
always arrays of strings, even for headers received just once.
29022905

2906+
The object has a null prototype and should not be accessed using the `in`
2907+
operator.
2908+
29032909
```js
29042910
// Prints something like:
29052911
//
@@ -3086,6 +3092,9 @@ added: v0.3.0
30863092

30873093
The request/response trailers object. Only populated at the `'end'` event.
30883094

3095+
The object has a null prototype and should not be accessed using the `in`
3096+
operator.
3097+
30893098
### `message.trailersDistinct`
30903099

30913100
<!-- YAML
@@ -3100,6 +3109,9 @@ Similar to [`message.trailers`][], but there is no join logic and the values are
31003109
always arrays of strings, even for headers received just once.
31013110
Only populated at the `'end'` event.
31023111

3112+
The object has a null prototype and should not be accessed using the `in`
3113+
operator.
3114+
31033115
### `message.url`
31043116

31053117
<!-- YAML

doc/api/http2.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4120,6 +4120,9 @@ The request/response headers object.
41204120

41214121
Key-value pairs of header names and values. Header names are lower-cased.
41224122

4123+
The object has a null prototype and should not be accessed using the `in`
4124+
operator.
4125+
41234126
```js
41244127
// Prints something like:
41254128
//
@@ -4279,6 +4282,9 @@ added: v8.4.0
42794282

42804283
The request/response trailers object. Only populated at the `'end'` event.
42814284

4285+
The object has a null prototype and should not be accessed using the `in`
4286+
operator.
4287+
42824288
#### `request.url`
42834289

42844290
<!-- YAML

0 commit comments

Comments
 (0)