Files
json/tools/api_checker/history/README.md
T
Niels Lohmann f23b3c63a2 Add AST-based public API checker and fix documentation gaps it found (#3691)
Adds tools/api_checker/: extract_api.py derives the public API surface directly
from the libclang AST (independent of documentation status), check_docs.py flags
public entries missing @sa links (and @sa on non-public ones), diff_api.py does
an overload-aware breaking/feature diff between two refs, check_macros.py cross-
checks documented macros against #define sites, and snapshot_release.py backfills
immutable per-release surface snapshots into tools/api_checker/history/ (v3.1.0
through v3.12.0) so diff_api.py can compare releases without live extraction.
POLICY.md documents what counts as public API and what stability is guaranteed.

Running this tooling against the current tree found and fixed a real documentation
backlog: ~25 new API doc pages (ordered_map's methods, json_sax's ctor/dtor/
operator=, byte_container_with_subtype's comparison operators, several orphaned
type aliases), each with a compiled and output-verified example, plus missing
@sa comments and stale/incorrect Version History entries on several existing
pages (found by diffing consecutive release pairs and checking whether the
resulting change was actually reflected in the target page's history section).

Also adds docs/home/api_changes.md, a per-release, per-function reference of
public API changes (v3.1.0 through v3.12.0) generated from the history/
snapshots, complementing (not replacing) the existing release notes.

Along the way, found and fixed several extractor bugs by testing against real
release tags rather than trusting the algorithm in isolation -- most notably an
identity-key scheme based on libclang's USR that encoded the enclosing class
template's own arity, and a since-renamed ABI inline-namespace pattern
(json_v3_11_0 vs. today's json_abi_v3_11_2) that neither of two earlier regex
attempts stripped correctly. Both are documented in extract_api.py's docstrings
and tools/api_checker/history/README.md so the failure mode doesn't recur
silently.

.github/workflows/check_api_docs.yml runs extract_api.py + check_docs.py in CI,
advisory-only for now (documented backlog may not be at zero for entities this
PR didn't touch), plus a blocking drift check on the committed
tools/api_checker/api_surface.json.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-11 18:59:00 +02:00

51 lines
3.2 KiB
Markdown

# API surface history
One file per released `v3.*` tag: `<tag>.json`, e.g. `v3.12.0.json`. Each is the output of
`extract_api.py --surface-output` at that tag (see `tools/api_checker/README.md` for the schema),
with additional immutable provenance in `meta`: `ref`, `commit` (the tag's resolved commit sha),
`generated_at`, and `generator`.
## Conventions
- **Immutable once committed.** Files here are never hand-edited or silently regenerated.
`snapshot_release.py` refuses to overwrite an existing file unless `--force` is passed, and that
should only happen for a deliberate, reviewed fix — the resulting diff should be inspected before
committing, same as any other source change.
- **Generated by `tools/api_checker/snapshot_release.py`**, run manually as part of cutting a
release (see `tools/api_checker/README.md`'s "Workflow: Release Checklist"). Not CI-automated.
- **`diff_api.py` uses these automatically.** `--old`/`--new` check here first (matching the ref
string to `<ref>.json`) before falling back to live `git archive` extraction — see
`tools/api_checker/README.md`'s `diff_api.py` section.
## Coverage
Backfilled: every `v3.*` tag from `v3.1.0` through the latest release at backfill time
(`v3.12.0`), covering the full public API history of the `include/nlohmann/` header layout.
## Format history
- **`format_version: 2`** (current). Fixed `extract_api.py`'s `ABI_TAG_PATTERN` to also strip the
pre-rename ABI inline-namespace form used by `v3.11.0`/`v3.11.1`: `json_v3_11_0` (no `_abi`
segment), renamed to today's `json_abi_v3_11_2`-style tag starting with `v3.11.2`. Under
`format_version: 1`, that older form wasn't recognized, so every `scope`/`signature` at
`v3.11.0`/`v3.11.1` retained the raw un-stripped namespace segment, making `diff_api.py` report
essentially the entire API (~330 of ~332 entries) as removed-and-readded across
`v3.10.5`->`v3.11.0`->`v3.11.1`->`v3.11.2` — a bug of the same shape as the earlier USR-arity
issue documented in `extract_api.py`'s `identity_key()` docstring, caught the same way: by
actually diffing real consecutive release pairs instead of trusting the extractor in isolation.
All 27 files were regenerated under `format_version: 2`; only `v3.11.0.json` and `v3.11.1.json`
actually changed content (every other tag's scopes never contained the old-style tag).
## Known gaps
- **`v3.0.0`, `v3.0.1`**: not backfilled. These predate the `include/nlohmann/` directory
structure entirely — headers lived under `src/` at that point (a single `src/json.hpp`). Since
`extract_api.py` hardcodes `include/nlohmann/json.hpp` as the entry point,
`snapshot_release.py --all-tags` fails cleanly on these two refs (`git archive ... -- include`
finds nothing) rather than silently producing a wrong/empty result. Not pursued: two tags,
immediately superseded by `v3.1.0`, and supporting the pre-restructuring layout would need a
separate header/include-path convention with no other benefit. If full pre-3.1 coverage is ever
wanted, `extract_api.py` would need a `src/json.hpp`-aware mode first.
- Pre-`v3.0.0` tags (`v1.x`, `v2.x`, `v3.0.0-rc*`, etc.) were never attempted — out of scope for
this backfill; see `tools/api_checker/POLICY.md` for the stated boundary.