+
+using json = nlohmann::json;
+
+int main()
+{
+ // create a JSON object with a string value
+ json j = {{"name", "the good"}};
+
+ // exception type_error.302
+ try
+ {
+ int v = j.value("name", 0);
+ std::cout << v << '\n';
+ }
+ catch (const json::type_error& e)
+ {
+ std::cout << e.what() << '\n';
+ }
+
+ // exception type_error.306
+ try
+ {
+ json str = "I am a string";
+ auto v = str.value("name", 0);
+ std::cout << v << '\n';
+ }
+ catch (const json::type_error& e)
+ {
+ std::cout << e.what() << '\n';
+ }
+}
diff --git a/docs/mkdocs/docs/examples/value__exception.output b/docs/mkdocs/docs/examples/value__exception.output
new file mode 100644
index 000000000..fab99f1f6
--- /dev/null
+++ b/docs/mkdocs/docs/examples/value__exception.output
@@ -0,0 +1,2 @@
+[json.exception.type_error.302] type must be number, but is string
+[json.exception.type_error.306] cannot use value() with string
diff --git a/docs/mkdocs/docs/features/arbitrary_types.md b/docs/mkdocs/docs/features/arbitrary_types.md
index 7ea01ee55..f7f3326ce 100644
--- a/docs/mkdocs/docs/features/arbitrary_types.md
+++ b/docs/mkdocs/docs/features/arbitrary_types.md
@@ -80,6 +80,29 @@ Some important things:
* In function `from_json`, use function [`at()`](../api/basic_json/at.md) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
+??? example "Example: serialize a `person` to JSON with `to_json`"
+
+ ```cpp
+ --8<-- "examples/to_json.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/to_json.output"
+ ```
+
+??? example "Example: deserialize a `person` from JSON with `from_json`"
+
+ ```cpp
+ --8<-- "examples/from_json__default_constructible.cpp"
+ ```
+
+ Output:
+
+ ```
+ --8<-- "examples/from_json__default_constructible.output"
+ ```
## Simplify your life with macros
@@ -98,7 +121,29 @@ There are several macros to make your life easier as long as you want to use a J
For all the macros, the first parameter is the name of the class/struct. The `DERIVED_TYPE` macros require a second parameter of a base class. All the remaining parameters name the member variables. The `WITH_NAMES` macros require a JSON name before each of the variables.
-| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro |
+```mermaid
+flowchart TD
+ A["choosing a NLOHMANN_DEFINE_* macro"] --> B{"adding fields to a base class?"}
+ B -->|"yes"| C["...DERIVED_TYPE..."]
+ B -->|"no"| D["...TYPE..."]
+ C --> E{"need access to private members?"}
+ D --> E
+ E -->|"yes"| F["...INTRUSIVE... (used inside the class)"]
+ E -->|"no"| G["...NON_INTRUSIVE... (used in the namespace)"]
+ F --> H{"only serializing, never parsing back?"}
+ G --> H
+ H -->|"yes"| I["...ONLY_SERIALIZE"]
+ H -->|"no"| J{"allow missing keys when parsing?"}
+ J -->|"yes"| K["...WITH_DEFAULT"]
+ J -->|"no"| L["plain (missing keys throw)"]
+ I --> M{"need custom JSON key names?"}
+ K --> M
+ L --> M
+ M -->|"yes"| N["...WITH_NAMES"]
+ M -->|"no"| O["done"]
+```
+
+| Need access to private members | Need only serialization | Allow missing values when de-serializing | macro |
|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_type_intrusive.md) |
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_type_intrusive.md) |
@@ -109,7 +154,7 @@ For all the macros, the first parameter is the name of the class/struct. The `DE
For _derived_ classes and structs, use the following macros
-| Need access to private members | Need only de-serialization | Allow missing values when de-serializing | macro |
+| Need access to private members | Need only serialization | Allow missing values when de-serializing | macro |
|------------------------------------------------------------------|------------------------------------------------------------------|------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-x-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE**](../api/macros/nlohmann_define_derived_type.md) |
| :octicons-check-circle-fill-24:
| :octicons-x-circle-fill-24:
| :octicons-check-circle-fill-24:
| [**NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT**](../api/macros/nlohmann_define_derived_type.md) |
@@ -124,7 +169,7 @@ For _derived_ classes and structs, use the following macros
types with more than 63 member variables, you need to define the `to_json`/`from_json` functions manually.
- For the `WITH_NAMES` variants the limit is halved to 31 member variables.
-??? example
+??? example "Example: using the `NLOHMANN_DEFINE_TYPE_*` macros"
The `to_json`/`from_json` functions for the `person` struct above can be created with:
@@ -245,6 +290,14 @@ For _derived_ classes and structs, use the following macros
This requires a bit more advanced technique. But first, let us see how this conversion mechanism works:
+```mermaid
+flowchart LR
+ A["construct json j = t, or call j.get() for T"] --> B["JSONSerializer for T: to_json / from_json"]
+ B -->|"default JSONSerializer"| C["adl_serializer for T: to_json / from_json"]
+ C -->|"unqualified call, found via ADL"| D["free to_json(j, t) / from_json(j, t) in T's namespace"]
+ B -->|"user specialization replaces the default"| E["user's adl_serializer specialization for T"]
+```
+
The library uses **JSON Serializers** to convert types to JSON.
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)).
@@ -300,7 +353,24 @@ NLOHMANN_JSON_NAMESPACE_END
## How can I use `get()` for non-default constructible/non-copyable types?
-There is a way if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
+For a type that is not [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible) but is
+otherwise an ordinary value type, specialize `adl_serializer` with a `from_json` overload that returns the value instead
+of writing into a reference:
+
+??? example "Example: `get()` for a non-default-constructible type"
+
+ ```cpp
+ --8<-- "examples/from_json__non_default_constructible.cpp"
+ ```
+
+ Output:
+
+ ```
+ --8<-- "examples/from_json__non_default_constructible.output"
+ ```
+
+The same technique also works if your type is not copyable, as long as it is
+[MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):
```cpp
struct move_only_type {
@@ -359,15 +429,10 @@ json any_to_json(const std::any& a) {
## Why does serializing a `std::map`/`std::unordered_map` with non-string keys produce an array?
-A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map`) is
-serialized as a JSON *array* of 2-element `[key, value]` arrays, not as a JSON object -- JSON object keys must be
-strings, so the library cannot represent an integer-keyed map as an object.
-
-```cpp
-std::map m{{1, "one"}, {2, "two"}};
-json j = m;
-// j is [[1,"one"],[2,"two"]], not {"1":"one","2":"two"}
-```
+A `std::map`/`std::unordered_map` whose key type is not string-like (e.g., `std::map`) cannot be
+serialized as a JSON object, because JSON object keys must be strings. See
+[Converting maps with non-string keys](types/index.md#converting-maps-with-non-string-keys) in the types article for
+what the library does instead.
## Why does `std::wstring` convert or dump incorrectly?
@@ -411,7 +476,7 @@ struct less_than_32_serializer {
Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention:
```cpp
-template
+template
struct bad_serializer
{
template
@@ -429,3 +494,10 @@ struct bad_serializer
}
};
```
+
+## See also
+
+- [Converting values](conversions.md) - the general overview of `get`/`get_to` and implicit conversions
+- [Specializing enum conversion](enum_conversion.md) - map enums to JSON strings instead of integers
+- [Supported macros](macros.md) - reference for `NLOHMANN_DEFINE_TYPE_*` and related macros
+- [`adl_serializer`](../api/adl_serializer/index.md) - the default `JSONSerializer` used in the conversion dispatch
diff --git a/docs/mkdocs/docs/features/assertions.md b/docs/mkdocs/docs/features/assertions.md
index 789af7989..e0b850115 100644
--- a/docs/mkdocs/docs/features/assertions.md
+++ b/docs/mkdocs/docs/features/assertions.md
@@ -27,7 +27,7 @@ If you are not sure whether an element in an object exists, use checked access w
See also the documentation on [element access](element_access/index.md).
-??? example "Example 1: Missing object key"
+??? example "Example: missing object key"
The following code will trigger an assertion at runtime:
@@ -54,7 +54,7 @@ See also the documentation on [element access](element_access/index.md).
Constructing a JSON value from an iterator range (see [constructor](../api/basic_json/basic_json.md)) with an
uninitialized iterator is undefined behavior and yields a runtime assertion.
-??? example "Example 2: Uninitialized iterator range"
+??? example "Example: uninitialized iterator range"
The following code will trigger an assertion at runtime:
@@ -81,7 +81,7 @@ uninitialized iterator is undefined behavior and yields a runtime assertion.
Any operation on uninitialized iterators (i.e., iterators that are not associated with any JSON value) is undefined
behavior and yields a runtime assertion.
-??? example "Example 3: Uninitialized iterator"
+??? example "Example: uninitialized iterator"
The following code will trigger an assertion at runtime:
@@ -112,7 +112,7 @@ library asserted that the pointer was not `nullptr` using a runtime assertion. I
result in undefined behavior. Since version 3.12.0, this library checks for `nullptr` and throws a
[`parse_error.101`](../home/exceptions.md#jsonexceptionparse_error101) to prevent the undefined behavior.
-??? example "Example 4: Reading from null pointer"
+??? example "Example: reading from null pointer"
The following code will trigger an assertion at runtime:
diff --git a/docs/mkdocs/docs/features/binary_formats/bjdata.md b/docs/mkdocs/docs/features/binary_formats/bjdata.md
index cd73b07e2..8e3ed41f6 100644
--- a/docs/mkdocs/docs/features/binary_formats/bjdata.md
+++ b/docs/mkdocs/docs/features/binary_formats/bjdata.md
@@ -73,7 +73,7 @@ The library uses the following mapping from JSON values types to BJData types ac
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the
- `dump()` function which serializes NaN or Infinity to `#!json null`.
+ [`dump()`](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `#!json null`.
!!! info "Endianness"
@@ -163,7 +163,7 @@ The library uses the following mapping from JSON values types to BJData types ac
[BJDataBinArr]: https://github.com/NeuroJSON/bjdata/blob/master/Binary_JData_Specification.md#optimized-binary-array
-??? example
+??? example "Example: serialize JSON values to BJData, with and without size/type optimization"
```cpp
--8<-- "examples/to_bjdata.cpp"
@@ -218,7 +218,7 @@ The library maps BJData types to JSON value types as follows:
binary values above), and serializing such an array again may choose different, but equally valid, type markers.
The bytes can then differ, but parsing them again yields the same value.
-??? example
+??? example "Example: deserialize a JSON value from BJData"
```cpp
--8<-- "examples/from_bjdata.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/bon8.md b/docs/mkdocs/docs/features/binary_formats/bon8.md
index 9b5fa1dda..d2d20da19 100644
--- a/docs/mkdocs/docs/features/binary_formats/bon8.md
+++ b/docs/mkdocs/docs/features/binary_formats/bon8.md
@@ -53,8 +53,9 @@ The library uses the following mapping from JSON values types to BON8 types acco
An integer that takes 2 to 4 bytes starts with a UTF-8 lead byte (0xC2..0xF7) that is followed by a byte that cannot
continue a UTF-8 character: 0x00..0x7F for positive and 0xC0..0xFF for negative integers. A string is terminated by
-0xFF only if it is empty, if another string follows it, or if it is the last value of the message; otherwise, the first
-byte of the next value ends it.
+0xFF only if it is empty, if another string follows it, or if nothing follows it in the message; otherwise, the byte
+after it ends it: the first byte of the next value, or the 0xFE that ends an array or object. For example, `["e"]` is
+serialized as 0x81 0x65 0xFF, but `[1,2,3,4,"e"]` as 0x85 0x91 0x92 0x93 0x94 0x65 0xFE.
!!! success "Complete mapping"
@@ -92,7 +93,7 @@ byte of the next value ends it.
- Object keys are written in the order of the object type, which is sorted for `json`, but not for
[`ordered_json`](../../api/ordered_json.md).
-??? example
+??? example "Example: serialize a JSON value to BON8"
```cpp
--8<-- "examples/to_bon8.cpp"
@@ -140,13 +141,13 @@ Non-negative integers are read as number_unsigned, negative integers as number_i
arrays and objects with up to four elements that are terminated by 0xFE, unsorted object keys, or a 0xFF after a
string that would also end without it, are accepted. A second 0xFF is not a terminator but an empty string.
- Strings must be valid UTF-8, and the last string of a message must be terminated by 0xFF.
+ Strings must be valid UTF-8, and a string at the very end of a message must be terminated by 0xFF.
!!! info
Any BON8 output created by `to_bon8` can be successfully parsed by `from_bon8`.
-??? example
+??? example "Example: deserialize a JSON value from BON8"
```cpp
--8<-- "examples/from_bon8.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/bson.md b/docs/mkdocs/docs/features/binary_formats/bson.md
index 6f5603c8c..cca11451e 100644
--- a/docs/mkdocs/docs/features/binary_formats/bson.md
+++ b/docs/mkdocs/docs/features/binary_formats/bson.md
@@ -48,7 +48,7 @@ The library uses the following mapping from JSON values types to BSON types:
As a result, serializing and deserializing a JSON object containing such a value produces a different JSON object,
even though the binary data is unchanged.
-??? example
+??? example "Example: serialize a JSON value to BSON"
```cpp
--8<-- "examples/to_bson.cpp"
@@ -118,7 +118,7 @@ The library maps BSON record types to JSON value types as follows:
(key) names and `binary` values (type `0x05`) are unaffected and are never validated, since they are read
byte-by-byte as a C string, or are not required to hold text, respectively.
-??? example
+??? example "Example: deserialize a JSON value from BSON"
```cpp
--8<-- "examples/from_bson.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/cbor.md b/docs/mkdocs/docs/features/binary_formats/cbor.md
index a488466d4..eb7bc7f41 100644
--- a/docs/mkdocs/docs/features/binary_formats/cbor.md
+++ b/docs/mkdocs/docs/features/binary_formats/cbor.md
@@ -98,7 +98,7 @@ see "binary" cells in the table above.
Binary subtypes will be serialized as tagged items. See [binary values](../binary_values.md#cbor) for an example.
-??? example
+??? example "Example: serialize a JSON value to CBOR"
```cpp
--8<-- "examples/to_cbor.cpp"
@@ -203,7 +203,7 @@ The library maps CBOR types to JSON value types as follows:
Tagged items (0xC0..0xDB) will throw a parse error by default. They can be ignored by passing `cbor_tag_handler_t::ignore` to function `from_cbor`, in which case the tag is skipped and the enclosed data item is parsed on its own. Passing `cbor_tag_handler_t::store` to function `from_cbor` stores tagged byte strings (for bytes 0xd8..0xdb) as binary values with the tag as subtype; other tagged values are read as if the tag were ignored. If several tags precede a byte string, only the innermost one is stored. Note that no tag is ever interpreted: for instance, a text string tagged with tag 0 (date/time) stays a string.
-??? example
+??? example "Example: deserialize a JSON value from CBOR"
```cpp
--8<-- "examples/from_cbor.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/messagepack.md b/docs/mkdocs/docs/features/binary_formats/messagepack.md
index 3ce5f7620..2e674252a 100644
--- a/docs/mkdocs/docs/features/binary_formats/messagepack.md
+++ b/docs/mkdocs/docs/features/binary_formats/messagepack.md
@@ -79,7 +79,7 @@ specification:
total), because the check used to select the smaller float 32 encoding compared magnitudes with NaN, which is
always `false` and caused the float 32 path to be skipped.
-??? example
+??? example "Example: serialize a JSON value to MessagePack"
```cpp
--8<-- "examples/to_msgpack.cpp"
@@ -162,7 +162,7 @@ The library maps MessagePack types to JSON value types as follows:
value is dumped. `bin`/`ext`/`fixext` values are unaffected and are never validated, since they are not required
to hold text.
-??? example
+??? example "Example: deserialize a JSON value from MessagePack"
```cpp
--8<-- "examples/from_msgpack.cpp"
diff --git a/docs/mkdocs/docs/features/binary_formats/ubjson.md b/docs/mkdocs/docs/features/binary_formats/ubjson.md
index be545b9fe..37aa069e2 100644
--- a/docs/mkdocs/docs/features/binary_formats/ubjson.md
+++ b/docs/mkdocs/docs/features/binary_formats/ubjson.md
@@ -11,29 +11,29 @@ achieve the generality of JSON, combined with being much easier to process than
The library uses the following mapping from JSON values types to UBJSON types according to the UBJSON specification:
-| JSON value type | value/range | UBJSON type | marker |
-|-----------------|-----------------------------------|----------------|--------|
-| null | `null` | null | `Z` |
-| boolean | `true` | true | `T` |
-| boolean | `false` | false | `F` |
-| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
-| number_integer | -2147483648..-32769 | int32 | `l` |
-| number_integer | -32768..-129 | int16 | `I` |
-| number_integer | -128..127 | int8 | `i` |
-| number_integer | 128..255 | uint8 | `U` |
-| number_integer | 256..32767 | int16 | `I` |
-| number_integer | 32768..2147483647 | int32 | `l` |
-| number_integer | 2147483648..9223372036854775807 | int64 | `L` |
-| number_unsigned | 0..127 | int8 | `i` |
-| number_unsigned | 128..255 | uint8 | `U` |
-| number_unsigned | 256..32767 | int16 | `I` |
-| number_unsigned | 32768..2147483647 | int32 | `l` |
-| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
-| number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` |
-| number_float | *any value* | float64 | `D` |
-| string | *with shortest length indicator* | string | `S` |
-| array | *see notes on optimized format* | array | `[` |
-| object | *see notes on optimized format* | map | `{` |
+| JSON value type | value/range | UBJSON type | marker |
+|-----------------|-------------------------------------------|----------------|--------|
+| null | `null` | null | `Z` |
+| boolean | `true` | true | `T` |
+| boolean | `false` | false | `F` |
+| number_integer | -9223372036854775808..-2147483649 | int64 | `L` |
+| number_integer | -2147483648..-32769 | int32 | `l` |
+| number_integer | -32768..-129 | int16 | `I` |
+| number_integer | -128..127 | int8 | `i` |
+| number_integer | 128..255 | uint8 | `U` |
+| number_integer | 256..32767 | int16 | `I` |
+| number_integer | 32768..2147483647 | int32 | `l` |
+| number_integer | 2147483648..9223372036854775807 | int64 | `L` |
+| number_unsigned | 0..127 | int8 | `i` |
+| number_unsigned | 128..255 | uint8 | `U` |
+| number_unsigned | 256..32767 | int16 | `I` |
+| number_unsigned | 32768..2147483647 | int32 | `l` |
+| number_unsigned | 2147483648..9223372036854775807 | int64 | `L` |
+| number_unsigned | 9223372036854775808..18446744073709551615 | high-precision | `H` |
+| number_float | *any value* | float64 | `D` |
+| string | *with shortest length indicator* | string | `S` |
+| array | *see notes on optimized format* | array | `[` |
+| object | *see notes on optimized format* | map | `{` |
!!! success "Complete mapping"
@@ -57,7 +57,7 @@ The library uses the following mapping from JSON values types to UBJSON types ac
!!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. This behavior differs from the
- `dump()` function which serializes NaN or Infinity to `null`.
+ [`dump()`](../../api/basic_json/dump.md) function which serializes NaN or Infinity to `null`.
!!! info "Optimized formats"
@@ -82,7 +82,7 @@ The library uses the following mapping from JSON values types to UBJSON types ac
documentation. In particular, this means that serialization and the deserialization of a JSON containing binary
values into UBJSON and back will result in a different JSON object.
-??? example
+??? example "Example: serialize JSON values to UBJSON, with and without size/type optimization"
```cpp
--8<-- "examples/to_ubjson.cpp"
@@ -120,7 +120,7 @@ The library maps UBJSON types to JSON value types as follows:
The mapping is **complete** in the sense that any UBJSON value can be converted to a JSON value.
-??? example
+??? example "Example: deserialize a JSON value from UBJSON"
```cpp
--8<-- "examples/from_ubjson.cpp"
diff --git a/docs/mkdocs/docs/features/binary_values.md b/docs/mkdocs/docs/features/binary_values.md
index aa3185c2a..98e8e71c3 100644
--- a/docs/mkdocs/docs/features/binary_values.md
+++ b/docs/mkdocs/docs/features/binary_values.md
@@ -27,7 +27,7 @@ vector <|-- binary_t
By default, binary values are stored as `std::vector`. This type can be changed by providing a template
parameter to the `basic_json` type. To store binary subtypes, the storage type is extended and exposed as
-`json::binary_t`:
+[`json::binary_t`](../api/basic_json/binary_t.md):
```cpp
auto binary = json::binary_t({0xCA, 0xFE, 0xBA, 0xBE});
@@ -62,21 +62,23 @@ JSON values can be constructed from `json::binary_t`:
json j = binary;
```
-Binary values are primitive values just like numbers or strings:
+Binary values are primitive values just like numbers or strings, as reflected by
+[`is_binary()`](../api/basic_json/is_binary.md) and [`is_primitive()`](../api/basic_json/is_primitive.md):
```cpp
j.is_binary(); // returns true
j.is_primitive(); // returns true
```
-Given a binary JSON value, the `binary_t` can be accessed by reference as via `get_binary()`:
+Given a binary JSON value, the `binary_t` can be accessed by reference via
+[`get_binary()`](../api/basic_json/get_binary.md):
```cpp
j.get_binary().has_subtype(); // returns true
j.get_binary().size(); // returns 4
```
-For convenience, binary JSON values can be constructed via `json::binary`:
+For convenience, binary JSON values can be constructed via [`json::binary`](../api/basic_json/binary.md):
```cpp
auto j2 = json::binary({0xCA, 0xFE, 0xBA, 0xBE}, 23);
@@ -99,7 +101,7 @@ JSON does not have a binary type, and this library does not introduce a new type
Instead, binary values are serialized as an object with two keys: `bytes` holds an array of integers, and `subtype`
is an integer or `null`.
-??? example
+??? example "Example: serialize a binary value to JSON"
Code:
@@ -133,7 +135,7 @@ is an integer or `null`.
[BJData](binary_formats/bjdata.md) neither supports binary values nor subtypes and proposes to serialize binary values
as an array of uint8 values. The library implements this translation.
-??? example
+??? example "Example: serialize a binary value to BJData"
Code:
@@ -192,7 +194,7 @@ as an array of uint8 values. The library implements this translation.
[BON8](binary_formats/bon8.md) neither supports binary values nor subtypes. The library serializes binary values as an
array of integers.
-??? example
+??? example "Example: serialize a binary value to BON8"
Code:
@@ -227,7 +229,7 @@ array of integers.
[BSON](binary_formats/bson.md) supports binary values and subtypes. If a subtype is given, it is used and added as an
unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00 is used.
-??? example
+??? example "Example: serialize a binary value to BSON"
Code:
@@ -269,7 +271,7 @@ unsigned 8-bit integer. If no subtype is given, the generic binary subtype 0x00
value will be serialized as byte strings. The library will choose the smallest representation using the length of the
byte array.
-??? example
+??? example "Example: serialize a binary value to CBOR"
Code:
@@ -294,7 +296,9 @@ byte array.
```
Note that the subtype is serialized as tag. However, parsing tagged values yield a parse error unless
- `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to `json::from_cbor`.
+ `json::cbor_tag_handler_t::ignore` or `json::cbor_tag_handler_t::store` is passed to
+ [`json::from_cbor`](../api/basic_json/from_cbor.md) (see
+ [`cbor_tag_handler_t`](../api/basic_json/cbor_tag_handler_t.md)).
```json
{
@@ -313,7 +317,7 @@ ext32. The subtype is then added as a signed 8-bit integer.
If no subtype is given, the bin family (bin8, bin16, bin32) is used.
-??? example
+??? example "Example: serialize a binary value to MessagePack"
Code:
@@ -353,7 +357,7 @@ If no subtype is given, the bin family (bin8, bin16, bin32) is used.
[UBJSON](binary_formats/ubjson.md) neither supports binary values nor subtypes and proposes to serialize binary values
as an array of uint8 values. The library implements this translation.
-??? example
+??? example "Example: serialize a binary value to UBJSON"
Code:
diff --git a/docs/mkdocs/docs/features/comments.md b/docs/mkdocs/docs/features/comments.md
index 95ac72359..86321bc4a 100644
--- a/docs/mkdocs/docs/features/comments.md
+++ b/docs/mkdocs/docs/features/comments.md
@@ -11,7 +11,7 @@ This library does not support comments *by default*. It does so for three reason
3. It is dangerous for interoperability if some libraries add comment support while others do not. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
-However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with `ignore_trailing_commas` (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
+However, you can set parameter `ignore_comments` to `#!cpp true` in the [`parse`](../api/basic_json/parse.md) function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace. Combined with [`ignore_trailing_commas`](trailing_commas.md) (also a `parse` parameter), this covers what is commonly referred to as **JSONC** (JSON with Comments, as used e.g. by Visual Studio Code's `.jsonc` files) -- comments and trailing commas, nothing more. This is a different, smaller extension than [JSON5](https://json5.org), which additionally allows unquoted keys, single-quoted strings, and other syntax changes that this library does not support.
For more information, see [JSON With Commas and Comments (JWCC)](https://nigeltao.github.io/blog/2021/json-with-commas-comments.html).
diff --git a/docs/mkdocs/docs/features/element_access/checked_access.md b/docs/mkdocs/docs/features/element_access/checked_access.md
index 1fb65e53b..d8dab0104 100644
--- a/docs/mkdocs/docs/features/element_access/checked_access.md
+++ b/docs/mkdocs/docs/features/element_access/checked_access.md
@@ -6,7 +6,7 @@ The [`at`](../../api/basic_json/at.md) member function performs checked access;
desired value if it exists and throws a [`basic_json::out_of_range` exception](../../home/exceptions.md#out-of-range)
otherwise.
-??? example "Read access"
+??? example "Example: read access"
Consider the following JSON value:
@@ -31,7 +31,7 @@ otherwise.
The return value is a reference, so it can be used to modify the original value.
-??? example "Write access"
+??? example "Example: write access"
```cpp
j.at("name") = "John Smith";
@@ -50,7 +50,7 @@ The return value is a reference, so it can be used to modify the original value.
When accessing an invalid index (i.e., an index greater than or equal to the array size) or the passed object key is
non-existing, an exception is thrown.
-??? example "Accessing via invalid index or missing key"
+??? example "Example: access via invalid index or missing key"
```cpp
j.at("hobbies").at(3) = "cooking";
diff --git a/docs/mkdocs/docs/features/element_access/default_value.md b/docs/mkdocs/docs/features/element_access/default_value.md
index 7b613062b..481448469 100644
--- a/docs/mkdocs/docs/features/element_access/default_value.md
+++ b/docs/mkdocs/docs/features/element_access/default_value.md
@@ -41,9 +41,9 @@ you want to access and a default value in case there is no value stored with tha
The value function is a template, and the return type of the function is determined by the type of the provided
default value unless otherwise specified. This can have unexpected effects. In the example below, we store a 64-bit
- unsigned integer. We get exactly that value when using [`operator[]`](../../api/basic_json/operator[].md). However,
- when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. This occurs, because `#!c 0`
- has type `#!c int` which overflows when handling the value `#!c 18446744073709551615`.
+ unsigned integer. We get exactly that value when using [`operator[]`](../../api/basic_json/operator%5B%5D.md).
+ However, when we call `value` and provide `#!c 0` as default value, then `#!c -1` is returned. This occurs,
+ because `#!c 0` has type `#!c int` which overflows when handling the value `#!c 18446744073709551615`.
To address this issue, either provide a correctly typed default value or use the template parameter to specify the
desired return type. Note that this issue occurs even when a value is stored at the provided key, and the default
diff --git a/docs/mkdocs/docs/features/element_access/index.md b/docs/mkdocs/docs/features/element_access/index.md
index 0b39547ec..262c057b8 100644
--- a/docs/mkdocs/docs/features/element_access/index.md
+++ b/docs/mkdocs/docs/features/element_access/index.md
@@ -5,5 +5,19 @@ There are many ways elements in a JSON value can be accessed:
- unchecked access via [`operator[]`](unchecked_access.md)
- checked access via [`at`](checked_access.md)
- access with default value via [`value`](default_value.md)
-- iterators
-- JSON pointers
+- [iterators](../iterators.md)
+- [JSON pointers](../json_pointer.md)
+
+Testing whether a key or index exists before accessing it is also possible, with
+[`contains`](../../api/basic_json/contains.md) or [`find`](../../api/basic_json/find.md) (which returns an iterator to
+the value, or `end()` if it is not found).
+
+```mermaid
+flowchart TD
+ A["accessing a value"] --> B{"must it exist?"}
+ B -->|"yes, missing is an error"| C["at() -- throws"]
+ B -->|"yes, but checking is my job"| D["operator[] -- unchecked"]
+ B -->|"no, a fallback is fine"| E["value() -- default value"]
+ A --> F{"just testing first?"}
+ F -->|"yes"| G["contains() / find()"]
+```
diff --git a/docs/mkdocs/docs/features/element_access/unchecked_access.md b/docs/mkdocs/docs/features/element_access/unchecked_access.md
index edaaa37a3..7e3f92ba1 100644
--- a/docs/mkdocs/docs/features/element_access/unchecked_access.md
+++ b/docs/mkdocs/docs/features/element_access/unchecked_access.md
@@ -5,7 +5,7 @@
Elements in a JSON object and a JSON array can be accessed via [`operator[]`](../../api/basic_json/operator%5B%5D.md)
similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively.
-??? example "Read access"
+??? example "Example: read access"
Consider the following JSON value:
@@ -31,7 +31,7 @@ similar to a `#!cpp std::map` and a `#!cpp std::vector`, respectively.
The return value is a reference, so it can modify the original value. In case the passed object key is non-existing, a
`#!json null` value is inserted which can immediately be overwritten.
-??? example "Write access"
+??? example "Example: write access"
```cpp
j["name"] = "John Smith";
@@ -52,7 +52,7 @@ The return value is a reference, so it can modify the original value. In case th
When accessing an invalid index (i.e., an index greater than or equal to the array size), the JSON array is resized such
that the passed index is the new maximal index. Intermediate values are filled with `#!json null`.
-??? example "Filling up arrays with `#!json null` values"
+??? example "Example: filling up arrays with `#!json null` values"
```cpp
j["hobbies"][0] = "running";
@@ -94,8 +94,8 @@ that the passed index is the new maximal index. Intermediate values are filled w
- It is **undefined behavior** to access a const object with a non-existing key.
- It is **undefined behavior** to access a const array with an invalid index.
- In debug mode, an **assertion** will fire in both cases. You can disable assertions by defining the preprocessor
- symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../macros.md#json_assertx). See the documentation
- on [runtime assertions](../assertions.md) for more information.
+ symbol `#!cpp NDEBUG` or redefine the macro [`JSON_ASSERT(x)`](../../api/macros/json_assert.md). See the
+ documentation on [runtime assertions](../assertions.md) for more information.
!!! failure "Exceptions"
@@ -105,8 +105,9 @@ that the passed index is the new maximal index. Intermediate values are filled w
## Performance: reserving array capacity
There is no public `reserve(count)` member on `basic_json` for pre-allocating array capacity. If you are building
-a large array incrementally (e.g., via repeated `push_back()`) and know its final size ahead of time, you can
-reserve capacity via `get_ref()` to access the underlying `array_t` directly:
+a large array incrementally (e.g., via repeated [`push_back()`](../../api/basic_json/push_back.md)) and know its final
+size ahead of time, you can reserve capacity via [`get_ref()`](../../api/basic_json/get_ref.md) to access the
+underlying `array_t` directly:
```cpp
json j = json::array();
diff --git a/docs/mkdocs/docs/features/enum_conversion.md b/docs/mkdocs/docs/features/enum_conversion.md
index d75d6e112..3efd8e818 100644
--- a/docs/mkdocs/docs/features/enum_conversion.md
+++ b/docs/mkdocs/docs/features/enum_conversion.md
@@ -29,6 +29,9 @@ The [`NLOHMANN_JSON_SERIALIZE_ENUM()` macro](../api/macros/nlohmann_json_seriali
## Usage
+Serialization converts an enum value to its mapped string, deserialization does the reverse, and an unrecognized JSON
+value deserializes to the first pair in the map:
+
```cpp
// enum to JSON as string
json j = TS_STOPPED;
@@ -43,6 +46,18 @@ json jPi = 3.14;
assert(jPi.get() == TS_INVALID );
```
+??? example "Example: serializing/deserializing enums, including a second enum type"
+
+ ```cpp
+ --8<-- "examples/nlohmann_json_serialize_enum.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/nlohmann_json_serialize_enum.output"
+ ```
+
## Notes
Just as in [Arbitrary Type Conversions](arbitrary_types.md) above,
@@ -54,9 +69,25 @@ Just as in [Arbitrary Type Conversions](arbitrary_types.md) above,
Other Important points:
-- When using `get()`, undefined JSON values will default to the first pair specified in your map. Select this
- default pair carefully. If you desire an exception in this circumstance use [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT()`](../api/macros/nlohmann_json_serialize_enum_strict.md)
- which behaves identically except for throwing an exception on unrecognized values.
+- When using [`get()`](../api/basic_json/get.md), undefined JSON values will default to the first pair
+ specified in your map. Select this default pair carefully. If you desire an exception in this circumstance use
+ [`NLOHMANN_JSON_SERIALIZE_ENUM_STRICT()`](../api/macros/nlohmann_json_serialize_enum_strict.md) which behaves
+ identically except for throwing an
+ [`out_of_range.410`](../home/exceptions.md#jsonexceptionout_of_range410) exception on unrecognized values, both when
+ serializing an enum value not listed in the map and when deserializing a JSON value that matches none of the map's
+ entries.
- If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the
map will be returned when converting to or from JSON.
- To disable the default serialization of enumerators as integers and force a compiler error instead, see [`JSON_DISABLE_ENUM_SERIALIZATION`](../api/macros/json_disable_enum_serialization.md).
+
+??? example "Example: `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` throwing on unrecognized values"
+
+ ```cpp
+ --8<-- "examples/nlohmann_json_serialize_enum_strict_err.cpp"
+ ```
+
+ Output:
+
+ ```json
+ --8<-- "examples/nlohmann_json_serialize_enum_strict_err.output"
+ ```
diff --git a/docs/mkdocs/docs/features/index.md b/docs/mkdocs/docs/features/index.md
index 246e47aee..d995c97d8 100644
--- a/docs/mkdocs/docs/features/index.md
+++ b/docs/mkdocs/docs/features/index.md
@@ -10,7 +10,8 @@ C++ types, and finally serialize it again.
understand the `#!cpp {}` vs. `#!cpp []` ambiguity.
- [Parsing](parsing/index.md) — read a JSON value from a string, file, or stream, including
[JSON Lines](parsing/json_lines.md), [callbacks](parsing/parser_callbacks.md), the
- [SAX interface](parsing/sax_interface.md), and [error handling](parsing/parse_exceptions.md).
+ [SAX interface](parsing/sax_interface.md), [error handling](parsing/parse_exceptions.md), and
+ [parsing untrusted input](parsing/untrusted_input.md).
- [Zero-copy JSON views](json_view.md) — read a JSON text through a flat index instead of building a `json` tree;
strings and numbers stay in the input and are only decoded when needed.
- [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar.
@@ -45,7 +46,10 @@ C++ types, and finally serialize it again.
- [Types](types/index.md) and [number handling](types/number_handling.md) — how JSON types map to C++ types and how
numbers are treated.
+- [Template parameter requirements](types/template_parameters.md) — what a type passed as one of `basic_json`'s
+ template parameters has to provide.
- [Object order](object_order.md) — keep insertion order with [`ordered_json`](../api/ordered_json.md).
+- [Performance](performance.md) — practical advice on parsing, memory use, serialization, and compile times.
- [Runtime assertions](assertions.md), [supported macros](macros.md), the [`nlohmann` namespace](namespace.md), and
[C++ modules](modules.md) — build-time and runtime configuration.
diff --git a/docs/mkdocs/docs/features/iterators.md b/docs/mkdocs/docs/features/iterators.md
index f45b92fdc..de493dd72 100644
--- a/docs/mkdocs/docs/features/iterators.md
+++ b/docs/mkdocs/docs/features/iterators.md
@@ -4,7 +4,10 @@
A `basic_json` value is a container and allows access via iterators. Depending on the value type, `basic_json` stores zero or more values.
-As for other containers, `begin()` returns an iterator to the first value and `end()` returns an iterator to the value following the last value. The latter iterator is a placeholder and cannot be dereferenced. In case of null values, empty arrays, or empty objects, `begin()` will return `end()`.
+As for other containers, [`begin()`](../api/basic_json/begin.md) returns an iterator to the first value and
+[`end()`](../api/basic_json/end.md) returns an iterator to the value following the last value. The latter iterator is a
+placeholder and cannot be dereferenced. In case of null values, empty arrays, or empty objects, `begin()` will return
+`end()`.

@@ -12,7 +15,7 @@ As for other containers, `begin()` returns an iterator to the first value and `e
When iterating over objects, values are ordered with respect to the `object_comparator_t` type which defaults to `std::less`. See the [types documentation](types/index.md#key-order) for more information.
-??? example
+??? example "Example: iteration order of object values"
```cpp
// create JSON object {"one": 1, "two": 2, "three": 3}
@@ -41,7 +44,7 @@ When iterating over objects, values are ordered with respect to the `object_comp
The JSON iterators have two member functions, `key()` and `value()` to access the object key and stored value, respectively. When calling `key()` on a non-object iterator, an [invalid_iterator.207](../home/exceptions.md#jsonexceptioninvalid_iterator207) exception is thrown.
-??? example
+??? example "Example: access object keys with `key()` and `value()`"
```cpp
// create JSON object {"one": 1, "two": 2, "three": 3}
@@ -76,7 +79,9 @@ for (auto it : j_object)
}
```
-For this reason, the `items()` function allows accessing `iterator::key()` and `iterator::value()` during range-based for loops. In these loops, a reference to the JSON values is returned, so there is no access to the underlying iterator.
+For this reason, the [`items()`](../api/basic_json/items.md) function allows accessing `iterator::key()` and
+`iterator::value()` during range-based for loops. In these loops, a reference to the JSON values is returned, so there
+is no access to the underlying iterator.
```cpp
for (auto& el : j_object.items())
@@ -104,11 +109,12 @@ for (auto& [key, val] : j_object.items())
### Reverse iteration order
-`rbegin()` and `rend()` return iterators in the reverse sequence.
+[`rbegin()`](../api/basic_json/rbegin.md) and [`rend()`](../api/basic_json/rend.md) return iterators in the reverse
+sequence.

-??? example
+??? example "Example: reverse iteration with `rbegin()` and `rend()`"
```cpp
json j = {1, 2, 3, 4};
@@ -132,7 +138,7 @@ for (auto& [key, val] : j_object.items())
Note that "value" means a JSON value in this setting, not values stored in the underlying containers. That is, `*begin()` returns the complete string or binary array and is also safe if the underlying string or binary array is empty.
-??? example
+??? example "Example: iterate over a string value"
```cpp
json j = "Hello, world";
diff --git a/docs/mkdocs/docs/features/json_patch.md b/docs/mkdocs/docs/features/json_patch.md
index 835f07f90..878f0084c 100644
--- a/docs/mkdocs/docs/features/json_patch.md
+++ b/docs/mkdocs/docs/features/json_patch.md
@@ -3,10 +3,17 @@
## Patches
JSON Patch ([RFC 6902](https://tools.ietf.org/html/rfc6902)) defines a JSON document structure for expressing a sequence
-of operations to apply to a JSON document. With the `patch` function, a JSON Patch is applied to the current JSON value
-by executing all operations from the patch.
+of operations to apply to a JSON document. Operations address locations in the document using
+[JSON Pointer](json_pointer.md) paths. With the [`patch`](../api/basic_json/patch.md) function, a JSON Patch is applied
+to the current JSON value by executing all operations from the patch, yielding the patched document as a new value.
-??? example
+!!! tip "Applying a patch without copying"
+
+ [`patch`](../api/basic_json/patch.md) leaves the original value unchanged and returns the patched result as a copy.
+ If the document is large and the original value is no longer needed,
+ [`patch_inplace`](../api/basic_json/patch_inplace.md) applies the same operations in place instead.
+
+??? example "Example: apply a JSON Patch"
The following code shows how a JSON patch is applied to a value.
@@ -22,7 +29,15 @@ by executing all operations from the patch.
## Diff
-The library can also calculate a JSON patch (i.e., a **diff**) given two JSON values.
+The library can also calculate a JSON patch (i.e., a **diff**) given two JSON values with the
+[`diff`](../api/basic_json/diff.md) function.
+
+```mermaid
+flowchart LR
+ S["source"] -->|"diff(source, target)"| P["patch"]
+ S -->|"source.patch(patch)"| T["target"]
+ P -.->|"applied to source, yields"| T
+```
!!! success "Invariant"
@@ -32,7 +47,7 @@ The library can also calculate a JSON patch (i.e., a **diff**) given two JSON va
source.patch(diff(source, target)) == target;
```
-??? example
+??? example "Example: create a JSON Patch from the difference of two values"
The following code shows how a JSON patch is created as a diff for two JSON values.
@@ -45,3 +60,11 @@ The library can also calculate a JSON patch (i.e., a **diff**) given two JSON va
```json
--8<-- "examples/diff.output"
```
+
+## See also
+
+- [JSON Pointer](json_pointer.md) - the addressing scheme used for patch paths
+- [JSON Merge Patch](merge_patch.md) - a simpler, less expressive alternative patch format
+- [`patch`](../api/basic_json/patch.md) - apply a JSON Patch, returning the result as a copy
+- [`patch_inplace`](../api/basic_json/patch_inplace.md) - apply a JSON Patch without copying
+- [`diff`](../api/basic_json/diff.md) - compute a JSON Patch from two values
diff --git a/docs/mkdocs/docs/features/json_pointer.md b/docs/mkdocs/docs/features/json_pointer.md
index c7237c266..786832c96 100644
--- a/docs/mkdocs/docs/features/json_pointer.md
+++ b/docs/mkdocs/docs/features/json_pointer.md
@@ -128,4 +128,5 @@ auto j_original = j_flat.unflatten();
- Class [`json_pointer`](../api/json_pointer/index.md)
- Function [`flatten`](../api/basic_json/flatten.md)
- Function [`unflatten`](../api/basic_json/unflatten.md)
-- [JSON Patch](json_patch.md)
+- [JSON Patch](json_patch.md) - paths inside a patch are JSON Pointers
+- [JSON Merge Patch](merge_patch.md) - an alternative patch format that does not use JSON Pointer
diff --git a/docs/mkdocs/docs/features/macros.md b/docs/mkdocs/docs/features/macros.md
index a4479712f..90bb352c3 100644
--- a/docs/mkdocs/docs/features/macros.md
+++ b/docs/mkdocs/docs/features/macros.md
@@ -179,7 +179,8 @@ See [full documentation of `JSON_USE_GLOBAL_UDLS`](../api/macros/json_use_global
## `JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`
When defined to `1`, the library restores the legacy behavior in which a discarded value compared equal to itself. This
-behavior is deprecated and switched off (`0`) by default.
+behavior is [deprecated](../integration/migration_guide.md#miscellaneous-functions) and switched off (`0`) by
+default.
See [full documentation of `JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../api/macros/json_use_legacy_discarded_value_comparison.md).
diff --git a/docs/mkdocs/docs/features/merge_patch.md b/docs/mkdocs/docs/features/merge_patch.md
index 84e0ab02f..46b0c5f04 100644
--- a/docs/mkdocs/docs/features/merge_patch.md
+++ b/docs/mkdocs/docs/features/merge_patch.md
@@ -1,9 +1,13 @@
# JSON Merge Patch
The library supports JSON Merge Patch ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format.
-The merge patch format is primarily intended for use with the HTTP PATCH method as a means of describing a set of modifications to a target resource's content. This function applies a merge patch to the current JSON value.
+The merge patch format is primarily intended for use with the HTTP PATCH method as a means of describing a set of
+modifications to a target resource's content. This function applies a merge patch to the current JSON value.
-Instead of using [JSON Pointer](json_pointer.md) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified.
+Instead of using [JSON Pointer](json_pointer.md) to specify values to be manipulated, it describes the changes using a
+syntax that closely mimics the document being modified. Unlike [JSON Patch](json_patch.md), a JSON Merge Patch cannot
+express every kind of change (e.g., it cannot reorder array elements or remove a specific array element), but it is
+easier to read and write for object-shaped documents.
??? example
@@ -18,3 +22,9 @@ Instead of using [JSON Pointer](json_pointer.md) to specify values to be manipul
```json
--8<-- "examples/merge_patch.output"
```
+
+## See also
+
+- [JSON Patch and Diff](json_patch.md) - a more expressive alternative that describes a sequence of operations
+- [JSON Pointer](json_pointer.md) - the addressing scheme used by JSON Patch
+- Function [`merge_patch`](../api/basic_json/merge_patch.md)
diff --git a/docs/mkdocs/docs/features/object_order.md b/docs/mkdocs/docs/features/object_order.md
index 200913fd2..b90637711 100644
--- a/docs/mkdocs/docs/features/object_order.md
+++ b/docs/mkdocs/docs/features/object_order.md
@@ -6,7 +6,7 @@ The [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as
The default type `nlohmann::json` uses a `std::map` to store JSON objects, and thus stores object keys **sorted alphabetically**.
-??? example
+??? example "Example: `json` sorts object keys"
```cpp
#include
@@ -39,7 +39,7 @@ The default type `nlohmann::json` uses a `std::map` to store JSON objects, and t
If you do want to preserve the **insertion order**, you can use the type [`nlohmann::ordered_json`](../api/ordered_json.md).
-??? example
+??? example "Example: `ordered_json` preserves insertion order"
```cpp
--8<-- "examples/ordered_json.cpp"
diff --git a/docs/mkdocs/docs/features/parsing/index.md b/docs/mkdocs/docs/features/parsing/index.md
index 476f024fa..9e5371d95 100644
--- a/docs/mkdocs/docs/features/parsing/index.md
+++ b/docs/mkdocs/docs/features/parsing/index.md
@@ -3,6 +3,16 @@
This library can create a JSON value from a wide range of inputs. This page gives an overview of the available parsing
functions and how they behave; the linked pages go into more detail.
+```mermaid
+flowchart LR
+ I["JSON input"] --> P["parse()"]
+ I --> S["sax_parse()"]
+ I --> A["accept()"]
+ P -->|"optional parser callback filters values"| D["basic_json value (DOM)"]
+ S --> H["events delivered to a user SAX handler"]
+ A --> V["bool: is the input valid JSON?"]
+```
+
## Input
The [`parse`](../../api/basic_json/parse.md) function reads a JSON value from an input. The input can be
@@ -76,3 +86,4 @@ options.
- [parser callbacks](parser_callbacks.md) - influence the parsing by a callback function
- [SAX interface](sax_interface.md) - implement a custom SAX handler
- [parsing and exceptions](parse_exceptions.md) - control error handling
+- [parsing untrusted input](untrusted_input.md) - what to consider when parsing input from untrusted sources
diff --git a/docs/mkdocs/docs/features/parsing/json_lines.md b/docs/mkdocs/docs/features/parsing/json_lines.md
index fb1481819..5ecf9d4af 100644
--- a/docs/mkdocs/docs/features/parsing/json_lines.md
+++ b/docs/mkdocs/docs/features/parsing/json_lines.md
@@ -46,8 +46,20 @@ JSON Lines input with more than one value is treated as invalid JSON by the [`pa
}
```
- with a JSON Lines input does not work, because the parser will try to parse one value after the last one.
+ with a JSON Lines input does not work, because the parser will try to parse one value after the last one and throw
+ a [`parse_error.101`](../../home/exceptions.md#jsonexceptionparse_error101) exception. The same happens for a
+ stream of *concatenated* (non-newline-delimited) JSON values: `operator>>` reads them one at a time, but the loop
+ above throws after the last value. To read either format with `operator>>`, check for the end of the stream before
+ each read:
- This is different from parsing a stream of *concatenated* (non-newline-delimited) JSON values, for which
- `operator>>` does work, provided that a value that is a number is followed by whitespace -- see its
- [notes](../../api/operator_gtgt.md#notes) for details.
+ ```cpp
+ json j;
+ while (input >> std::ws && input.peek() != std::char_traits::eof())
+ {
+ input >> j;
+ std::cout << j << std::endl;
+ }
+ ```
+
+ A value that is a number must be followed by whitespace -- see the [notes](../../api/operator_gtgt.md#notes) of
+ `operator>>` for details.
diff --git a/docs/mkdocs/docs/features/parsing/parse_exceptions.md b/docs/mkdocs/docs/features/parsing/parse_exceptions.md
index 25b4768ff..f524b67d8 100644
--- a/docs/mkdocs/docs/features/parsing/parse_exceptions.md
+++ b/docs/mkdocs/docs/features/parsing/parse_exceptions.md
@@ -23,9 +23,9 @@ In case exceptions are undesired or not supported by the environment, there are
## Switch off exceptions
-The `parse()` function accepts a `#!cpp bool` parameter `allow_exceptions` which controls whether an exception is
-thrown when a parse error occurs (`#!cpp true`, default) or whether a discarded value should be returned
-(`#!cpp false`).
+The [`parse()`](../../api/basic_json/parse.md) function accepts a `#!cpp bool` parameter `allow_exceptions` which
+controls whether an exception is thrown when a parse error occurs (`#!cpp true`, default) or whether a discarded value
+should be returned (`#!cpp false`).
```cpp
json j = json::parse(my_input, nullptr, false);
@@ -39,8 +39,8 @@ Note there is no diagnostic information available in this scenario.
## Use accept() function
-Alternatively, function `accept()` can be used which does not return a `json` value, but a `#!cpp bool` indicating
-whether the input is valid JSON.
+Alternatively, function [`accept()`](../../api/basic_json/accept.md) can be used which does not return a `json` value,
+but a `#!cpp bool` indicating whether the input is valid JSON.
```cpp
if (!json::accept(my_input))
@@ -66,56 +66,18 @@ bool parse_error(std::size_t position,
The return value indicates whether the parsing should continue, so the function should usually return `#!cpp false`.
-??? example
+??? example "Example: report parse errors without exceptions"
+
+ The example derives from the library's DOM parser and overrides `parse_error` to print the error instead of
+ throwing. Note the DOM parser is an implementation detail (`nlohmann::detail`) and may change between releases;
+ see [Do not use the `detail` namespace](../../integration/migration_guide.md#do-not-use-the-detail-namespace).
```cpp
- #include
- #include
-
- using json = nlohmann::json;
-
- class sax_no_exception : public nlohmann::detail::json_sax_dom_parser
- {
- public:
- sax_no_exception(json& j)
- : nlohmann::detail::json_sax_dom_parser(j, false)
- {}
-
- bool parse_error(std::size_t position,
- const std::string& last_token,
- const json::exception& ex)
- {
- std::cerr << "parse error at input byte " << position << "\n"
- << ex.what() << "\n"
- << "last read: \"" << last_token << "\""
- << std::endl;
- return false;
- }
- };
-
- int main()
- {
- std::string myinput = "[1,2,3,]";
-
- json result;
- sax_no_exception sax(result);
-
- bool parse_result = json::sax_parse(myinput, &sax);
- if (!parse_result)
- {
- std::cerr << "parsing unsuccessful!" << std::endl;
- }
-
- std::cout << "parsed value: " << result << std::endl;
- }
+ --8<-- "examples/sax_no_exception.cpp"
```
Output:
-
+
```
- parse error at input byte 8
- [json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal
- last read: "3,]"
- parsing unsuccessful!
- parsed value: [1,2,3]
+ --8<-- "examples/sax_no_exception.output"
```
diff --git a/docs/mkdocs/docs/features/parsing/parser_callbacks.md b/docs/mkdocs/docs/features/parsing/parser_callbacks.md
index e65ac0eb9..6144011ec 100644
--- a/docs/mkdocs/docs/features/parsing/parser_callbacks.md
+++ b/docs/mkdocs/docs/features/parsing/parser_callbacks.md
@@ -2,8 +2,9 @@
## Overview
-With a parser callback function, the result of parsing a JSON text can be influenced. When passed to `parse`, it is
-called on certain events (passed as `parse_event_t` via parameter `event`) with a set recursion depth `depth` and
+With a parser callback function, the result of parsing a JSON text can be influenced. When passed to
+[`parse`](../../api/basic_json/parse.md), it is called on certain events (passed as
+[`parse_event_t`](../../api/basic_json/parse_event_t.md) via parameter `event`) with a set recursion depth `depth` and
context JSON value `parsed`. The return value of the callback function is a boolean indicating whether the element that
emitted the callback shall be kept or not.
@@ -30,7 +31,7 @@ table describes the values of the parameters `depth`, `event`, and `parsed`.
| `parse_event_t::array_end` | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array |
| `parse_event_t::value` | the parser finished reading a JSON value | depth of the value | the parsed JSON value |
-??? example
+??? example "Example: sequence of callback events"
When parsing the following JSON text,
@@ -76,7 +77,7 @@ was called:
- In case a value outside a structured type is skipped, it is replaced with `#!json null`. This case happens if the
top-level element is skipped.
-??? example
+??? example "Example: skip an object key while parsing"
The example below demonstrates the `parse()` function with and without callback function.
@@ -98,7 +99,7 @@ the resulting `#!c json` value -- once parsing has produced that value, the dupl
storage maps each key to a single value. If duplicate keys should instead be treated as an error, a parser callback
can detect them while the object is still being read, before that ambiguity ever applies.
-??? example
+??? example "Example: reject duplicate object keys"
```cpp
--8<-- "examples/reject_duplicate_keys.cpp"
@@ -110,16 +111,18 @@ can detect them while the object is still being read, before that ambiguity ever
--8<-- "examples/reject_duplicate_keys.output"
```
-This approach has two limitations:
+This approach has three limitations:
- The depth-indexed bookkeeping must account for the fact that `object_start` reports the depth of the *parent* of
the object, while the `key` events inside that object are reported one depth deeper (see the event table above);
it is easy to get this off by one for nested objects.
- The thrown exception cannot carry a `parse_error`-style byte offset, because position tracking only exists inside
the parser and lexer, not at the callback layer.
+- The exception only names the repeated key, not where it occurs in the document. Reporting its full path requires
+ maintaining a stack of the enclosing keys and array indices in the callback as well.
-For strict validation with precise error positions, implementing a [SAX interface](sax_interface.md) instead gives
-access to the parser's position information directly.
+A [SAX interface](sax_interface.md) does not lift the position limitation: its `key` function receives no position
+either -- only `parse_error` is passed the byte position.
## Recipe: streaming a large homogeneous array
@@ -129,7 +132,7 @@ discard it, so memory usage stays bounded by a single element (plus the not-yet-
than the whole document. Since the top-level array's `array_start`/`array_end` are reported at `depth == 0` (its
parent is the document root), the object elements it contains are reported at `depth == 1`:
-??? example
+??? example "Example: stream a large top-level array"
```cpp
std::ifstream input("large_array.json");
@@ -154,7 +157,7 @@ homogeneous values by checking `object_end`/`value` events at `depth == 1` there
Since there is no built-in nesting-depth limit (see the note above), a callback can enforce one manually by
tracking the maximum `depth` seen and throwing once it is exceeded:
-??? example
+??? example "Example: limit the nesting depth"
```cpp
constexpr int max_depth = 32;
diff --git a/docs/mkdocs/docs/features/parsing/untrusted_input.md b/docs/mkdocs/docs/features/parsing/untrusted_input.md
new file mode 100644
index 000000000..d39a4179e
--- /dev/null
+++ b/docs/mkdocs/docs/features/parsing/untrusted_input.md
@@ -0,0 +1,163 @@
+# Parsing Untrusted Input
+
+This page is for applications that parse JSON -- or one of the supported [binary formats](../binary_formats/index.md)
+(BJData, BON8, BSON, CBOR, MessagePack, UBJSON) -- from a source they do not fully control, such as a network
+connection, an uploaded file, or another process. It summarizes what the library already does for such input and what
+remains the caller's responsibility, linking to the pages that cover each aspect in detail rather than repeating them.
+
+For the project's threat model and the countermeasures behind these behaviors, see the
+[assurance case](../../community/assurance_case.md); to report a vulnerability, see the
+[security policy](../../community/security_policy.md).
+
+## Errors without exceptions
+
+By default, [`parse()`](../../api/basic_json/parse.md) throws a
+[`parse_error`](../../home/exceptions.md#jsonexceptionparse_error101) (for instance `parse_error.101` for a syntax
+error) when the input is not valid. If your environment cannot use exceptions for untrusted input, the library offers
+several alternatives; see [Parsing and exceptions](parse_exceptions.md) for the full comparison:
+
+- Pass `#!cpp false` as the third argument to `parse()` to get a discarded value
+ (checked with [`is_discarded()`](../../api/basic_json/is_discarded.md)) instead of a thrown exception, with no
+ diagnostic information.
+- Use [`accept()`](../../api/basic_json/accept.md) to only check whether the input is valid JSON, without building a
+ value.
+- Implement the [SAX interface](sax_interface.md) and override `parse_error()` to react to an error yourself, with the
+ byte position and the exception that would otherwise have been thrown; see the
+ [example](parse_exceptions.md#user-defined-sax-interface) that overrides it to print instead of throw.
+
+If exceptions are unavailable entirely (`-fno-exceptions`, or [`JSON_NOEXCEPTION`](../../api/macros/json_noexception.md)
+defined), every `#!cpp throw` in the library becomes a call to `std::abort()` -- there is no way to recover from a
+parse error of untrusted input in that configuration; see
+[Switch off exceptions](../../home/exceptions.md#switch-off-exceptions) for the details and for overriding this with
+`JSON_THROW_USER`.
+
+## Nesting depth
+
+The JSON parser and the binary readers are iterative: they keep the containers they are currently inside of on a
+heap-allocated stack instead of calling themselves once per nesting level, so the native call stack does not grow with
+the nesting depth of the input. A deeply nested document is therefore bounded by available memory, not by the call
+stack, however deeply it is nested.
+
+!!! warning "No built-in depth limit while parsing"
+
+ Neither the parser nor the binary readers impose a limit on how deep the input may nest. An attacker can still
+ exhaust memory (though not the call stack) with a sufficiently deep document. If you need to reject over-deep
+ untrusted input outright, track the depth yourself, either with a
+ [parser callback](parser_callbacks.md#recipe-max-nesting-depth-via-a-callback) for the JSON parser, or by counting
+ `start_object`/`start_array` and `end_object`/`end_array` calls in a
+ [SAX handler](sax_interface.md) (for the JSON parser or a binary format alike) and throwing once your limit is
+ exceeded.
+
+Once a value has been parsed, operations that walk it recursively -- serializing it with
+[`dump`](../../api/basic_json/dump.md), hashing it, copying it, comparing two values with `#!cpp ==`, `#!cpp <`, or (in
+C++20) `#!cpp <=>`, merging with [`update`](../../api/basic_json/update.md), and applying a
+[`merge_patch`](../../api/basic_json/merge_patch.md) -- descend at most 128 levels on the call stack and continue
+below that with an explicit stack instead, so none of them can exhaust the stack either, however deeply the value is
+nested. Destroying a value (its destructor) never recurses at all, regardless of nesting depth, for the same reason.
+
+!!! note "Not every operation is bounded yet"
+
+ [`diff`](../../api/basic_json/diff.md), [`flatten`](../../api/basic_json/flatten.md), and the binary writers
+ (`to_cbor`, `to_msgpack`, ...) still recurse once per nesting level; this is called out as work in progress in the
+ [assurance case](../../community/assurance_case.md#secure-design). A value deep enough to matter for these
+ operations would typically first have to survive parsing without hitting a self-imposed depth limit, as described
+ above.
+
+## Input size
+
+The library does not limit the overall size of a JSON text; a value nested or wide enough will use memory
+proportional to the input. If you parse untrusted input of unbounded size, check the size of the file or stream
+yourself before -- or while -- handing it to `parse()`.
+
+For the binary formats, an announced size is never trusted outright:
+
+- Reading a string or binary value copies the input in bounded 4096-byte chunks and grows the result as bytes are
+ actually consumed, rather than allocating the announced length up front -- a truncated input runs out of bytes
+ (reported as a parse error) instead of triggering an oversized allocation.
+- When an array announces its number of elements and the array container supports `reserve()` (as `#!cpp std::vector`,
+ the default, does), the library reserves storage for at most 16384 of them upfront, regardless of how large the
+ announced count is; further elements still grow the container normally as they are read.
+- An announced array or object size that exceeds what the target container could ever hold (its `max_size()`) is
+ rejected immediately as [`out_of_range.408`](../../home/exceptions.md#jsonexceptionout_of_range408), without
+ attempting to allocate anything.
+
+## Strings
+
+Invalid UTF-8 is rejected while parsing, not just while serializing:
+
+- In JSON text, an ill-formed UTF-8 byte in a string is a
+ [`parse_error.101`](../../home/exceptions.md#jsonexceptionparse_error101) ("invalid string: ill-formed UTF-8 byte").
+- In a binary format, a string that is not valid UTF-8 is a
+ [`parse_error.113`](../../home/exceptions.md#jsonexceptionparse_error113).
+
+A `#!cpp '\0'` (NUL) byte *inside* a quoted JSON string is always rejected (it must be escaped as `\u0000`). A NUL byte
+*outside* of a string is different: by default it is silently treated as the end of the input, so trailing bytes after
+it -- including further, otherwise well-formed JSON -- are silently ignored rather than rejected. Since untrusted input
+that happens to embed a NUL is a way to make part of it disappear without a parse error, see the
+[FAQ entry](../../home/faq.md#nul-bytes-in-the-input) and consider defining
+[`JSON_STRICT_NUL_HANDLING`](../../api/macros/json_strict_nul_handling.md) to `1` to reject a NUL byte like any other
+unexpected byte instead.
+
+Parsing is not the only place invalid UTF-8 matters: a string that reached a `#!cpp json` value some other way (for
+example, constructed by application code, or, before JSON_STRICT_NUL_HANDLING existed, read from a binary format that
+does not validate strings) still has to round-trip back to JSON text. By default,
+[`dump()`](../../api/basic_json/dump.md) throws [`type_error.316`](../../home/exceptions.md#jsonexceptiontype_error316)
+if the string is not valid UTF-8; passing
+[`error_handler_t::replace`](../../api/basic_json/error_handler_t.md) or `error_handler_t::ignore` avoids the exception
+instead of crashing an application that forgot to catch it. See
+[Handling invalid UTF-8](../serialization.md#handling-invalid-utf-8) for the options and an example.
+
+## Duplicate object keys
+
+The JSON specification leaves the handling of repeated keys in an object up to the implementation, and this library
+does too: as described in [`object_t`](../../api/basic_json/object_t.md#behavior), it is unspecified which of the
+values for a repeated key ends up in the parsed object. If your application must reject duplicate keys instead of
+silently resolving them one way or another, see the
+[parser callback recipe for rejecting duplicate keys](parser_callbacks.md#recipe-rejecting-duplicate-object-keys).
+
+## Numbers
+
+A number whose value cannot be represented -- for instance `1E1000`, which overflows `double` -- is rejected while
+parsing as [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406) rather than silently becoming
+infinity. An integer that is syntactically valid but does not fit the 64-bit integer types is not rejected; it is
+instead stored as a `double`, which may lose precision for very large values. See
+[number limits](../types/number_handling.md#number-limits) for the exact ranges and an example.
+
+## Comments and trailing commas
+
+Both [comments](../comments.md) and [trailing commas](../trailing_commas.md) are rejected by default, matching the
+JSON specification; they must be explicitly enabled per call with the `ignore_comments` and `ignore_trailing_commas`
+parameters of [`parse()`](../../api/basic_json/parse.md) or [`accept()`](../../api/basic_json/accept.md). Do not
+enable either for input whose conformance you cannot otherwise control, since interoperability with strictly
+conforming JSON consumers is exactly what the default rejects.
+
+## Checklist
+
+- Wrap parsing in a `#!cpp try`/`#!cpp catch` block, or use `allow_exceptions=false`/`accept()` if your environment
+ cannot use exceptions; never let `JSON_NOEXCEPTION`'s `abort()` be the first time you think about error handling.
+- If the input's nesting depth matters to you, enforce your own limit with a
+ [parser callback](parser_callbacks.md#recipe-max-nesting-depth-via-a-callback) or a
+ [SAX handler](sax_interface.md); the library bounds the call stack but not memory use.
+- Bound the size of the input itself before parsing, independent of the library's own bounded allocations for binary
+ format lengths.
+- Decide up front how you want a string with invalid UTF-8 -- from any source, not only parsing -- to be serialized
+ (`strict`, `replace`, or `ignore`), rather than discovering it from an uncaught `type_error.316`.
+- If a stray NUL byte silently truncating trailing input is a problem for your input format, define
+ `JSON_STRICT_NUL_HANDLING`.
+- Decide whether duplicate object keys should be an error for your application, and add a callback if so.
+- Do not enable `ignore_comments` or `ignore_trailing_commas` for input that must be strictly conforming JSON.
+
+For the broader design rationale and how it is tested (fuzzing, sanitizers, static analysis), see the
+[assurance case](../../community/assurance_case.md) and [quality assurance](../../community/quality_assurance.md). To
+report a security issue in the library itself, follow the [security policy](../../community/security_policy.md).
+
+## See also
+
+- [Parsing](index.md) - overview of the parsing functions
+- [Parsing and exceptions](parse_exceptions.md) - error handling without exceptions
+- [Parser callbacks](parser_callbacks.md) - depth limits, duplicate-key rejection, and streaming recipes
+- [SAX interface](sax_interface.md) - implement a custom handler with access to parse errors and positions
+- [Serialization](../serialization.md) - handling invalid UTF-8 when dumping
+- [Number handling](../types/number_handling.md) - number ranges and overflow behavior
+- [Assurance case](../../community/assurance_case.md) - the library's threat model and countermeasures
+- [Security policy](../../community/security_policy.md) - how to report a vulnerability
diff --git a/docs/mkdocs/docs/features/performance.md b/docs/mkdocs/docs/features/performance.md
new file mode 100644
index 000000000..d6e9f70fd
--- /dev/null
+++ b/docs/mkdocs/docs/features/performance.md
@@ -0,0 +1,215 @@
+# Performance
+
+Speed was never the primary goal of this library. The [design goals](../home/design_goals.md) page says so plainly:
+"There are certainly faster JSON libraries out there." Intuitive syntax, trivial integration, and thorough testing came
+first. If a hard real-time budget or the last percent of throughput matters more than convenience, a
+[faster, more specialized library](https://github.com/miloyip/nativejson-benchmark#parsing-time) may be a better fit.
+
+That said, how you use this library still makes a measurable difference. This page collects practical, code-verified
+techniques for reducing time, memory, and compile-time cost -- without repeating the detailed pages it links to.
+
+## Parsing input
+
+[`parse`](../api/basic_json/parse.md) accepts a string, a pair of iterators, a container, a `#!cpp std::istream`, or a
+`#!cpp FILE*` (see [Parsing](parsing/index.md#input)). Internally, every input is wrapped in an
+[input adapter](../home/architecture.md#input-adapters), and not all adapters are equally fast.
+
+For inputs backed by contiguous, single-byte memory -- a `#!cpp std::string`, a `#!cpp std::vector`, a string
+literal, or a pointer range -- the library uses `iterator_input_adapter`, wrapped in a raw pointer so the fast paths
+below apply on every supported standard. This adapter exposes two optimizations the lexer detects at compile time:
+
+- it can reconstruct already-consumed input on demand for error messages, instead of copying every character as it is
+ read, and
+- the lexer can scan ordinary string characters directly out of the buffer, several bytes at a time, rather than one
+ character (and one function call) at a time.
+
+A `#!cpp std::istream` (including `#!cpp std::ifstream`) or `#!cpp FILE*`, by contrast, is read through
+`input_stream_adapter` or `file_input_adapter`, which read one character (or one block, for binary formats) at a time
+and expose neither optimization -- the lexer falls back to the same byte-at-a-time path it uses for any
+non-contiguous, general-purpose iterator range. An iterator pair over non-contiguous but random-access storage (e.g.
+`#!cpp std::deque::iterator`) gets the first optimization but not the second, since the byte-scanning fast path
+additionally requires contiguous storage.
+
+Practically: if the JSON text is already in memory, or small enough to read into memory, prefer passing a
+`#!cpp std::string`, a `#!cpp std::vector`, or a pointer range to `parse` over a `#!cpp std::istream`. For a
+file, that means reading it into a string first and then parsing the string, rather than passing a
+`#!cpp std::ifstream` directly to `parse` -- the latter never benefits from either optimization:
+
+```cpp
+// gets the contiguous fast paths
+std::ifstream f("example.json");
+std::string contents((std::istreambuf_iterator(f)), std::istreambuf_iterator());
+json j = json::parse(contents);
+
+// does not: input_stream_adapter has no fast path
+std::ifstream f2("example.json");
+json j2 = json::parse(f2);
+```
+
+For contiguous input with many non-ASCII characters, [`JSON_USE_SIMDUTF`](../api/macros/json_use_simdutf.md) can
+additionally speed up UTF-8 validation by using the [simdutf](https://github.com/simdutf/simdutf) library instead of
+the built-in scalar validator; streaming inputs (files, `#!cpp std::istream`, wide strings, user-defined adapters)
+always use the scalar path regardless of this macro.
+
+## Large documents
+
+Parsing always produces SAX events internally; [`parse`](../api/basic_json/parse.md) simply feeds them to a consumer
+that builds a complete `basic_json` value tree (a DOM) in memory. For documents too large to comfortably hold as
+a DOM, two alternatives avoid building it:
+
+- Implement the [SAX interface](parsing/sax_interface.md) directly and pass it to
+ [`sax_parse`](../api/basic_json/sax_parse.md); only the parts of the input you choose to keep ever become
+ `basic_json` values.
+- Pass a [parser callback](parsing/parser_callbacks.md) to `parse`. This still builds a DOM, but the callback can
+ discard finished elements as soon as they are handled, so memory usage stays bounded by one element (plus the
+ unparsed remainder of the input) instead of the whole document -- see the [recipe for streaming a large homogeneous
+ array](parsing/parser_callbacks.md#recipe-streaming-a-large-homogeneous-array).
+
+If the data is naturally record-oriented, consider [JSON Lines](parsing/json_lines.md) instead of one large JSON
+document: reading and parsing it line by line with `#!cpp std::getline` means only one line's value is ever in memory
+at a time, and a malformed line does not invalidate lines already processed.
+
+## Binary formats
+
+JSON text is not a compact format. If the data is only exchanged between programs (not read by humans), the
+[binary formats](binary_formats/index.md) -- BJData, BON8, BSON, CBOR, MessagePack, and UBJSON -- encode the same
+values more compactly, which reduces both the bytes transferred and, for most of them, the work needed to parse them
+back. The [size comparison](binary_formats/index.md#sizes) on that page, measured against minified JSON for four
+reference documents, shows the effect varies a lot by document shape: CBOR and MessagePack come out at 50.5% of the
+minified JSON size for the numeric-array-heavy `canada.json`, but only around 87-88% for the string-heavy
+`jeopardy.json`, where there is less numeric data to encode more compactly. BON8 is the most compact option in that
+comparison for text-heavy documents (63.5%-87.5%), at the cost of an
+[incomplete serializer](binary_formats/index.md#completeness) (no unsigned integers above int64). Which format -- and
+whether it is worth the loss of human readability at all -- depends on the actual data; see the
+[comparison tables](binary_formats/index.md#comparison) before choosing one.
+
+## Object type: `json` vs. `ordered_json`
+
+The default [`json`](../api/json.md) type stores object keys in a `#!cpp std::map`, giving logarithmic-time lookup,
+insertion, and erasure, at the cost of sorting keys alphabetically rather than preserving insertion order (see
+[Object Order](object_order.md)). [`ordered_json`](../api/ordered_json.md) uses
+[`nlohmann::ordered_map`](../api/ordered_map.md) instead, a `#!cpp std::vector`-backed container with no lookup index:
+every key-based operation is a **linear scan**, so building an object of `n` distinct keys costs **O(n²)** in total --
+this applies equally to inserting keys one by one and to parsing an object, since the parser inserts each key as it is
+read. The [measurements on the `ordered_map` page](../api/ordered_map.md#complexity) show this is
+negligible at typical object sizes (2000 keys: 0.7 ms for `json` vs. 3.6 ms for `ordered_json`, a 5x factor) but grows
+steeply for large, machine-generated objects (16 000 keys: 3.3 ms vs. 181.6 ms, a 54x factor).
+
+If insertion order matters *and* an object routinely has many thousands of keys, `ordered_json`'s quadratic build cost
+may not be acceptable. The library's [`ObjectType` template parameter](types/template_parameters.md#objecttype) can be
+set to a different container instead: `#!cpp nlohmann::fifo_map` keeps insertion order with a real lookup index
+(avoiding the quadratic cost), while `#!cpp std::unordered_map`, `#!cpp boost::unordered_flat_map`,
+`#!cpp absl::flat_hash_map`, and similar hash maps trade insertion order for average-case constant-time lookup (through
+an adapter, since their template argument order does not match what `basic_json` expects) -- see
+[Object Order](object_order.md#alternative-behavior-preserve-insertion-order) for the full list.
+
+## Avoiding copies
+
+- **Move instead of copy.** Constructing a `basic_json` from an existing one is
+ [linear in its size](../api/basic_json/basic_json.md#complexity) for the copy constructor but
+ [constant](../api/basic_json/basic_json.md#complexity) for the move constructor. The same applies to assigning a
+ large `#!cpp std::string`, `#!cpp std::vector`, or other container into a value: pass it as `#!cpp std::move(x)`
+ rather than `x` whenever `x` is no longer needed afterwards.
+- **Access without copying.** [`get()`](../api/basic_json/get.md) returns a copy of the stored value converted to
+ `T`. When a reference or pointer to the value already stored inside the `basic_json` is enough,
+ [`get_ref()`](../api/basic_json/get_ref.md) and [`get_ptr()`](../api/basic_json/get_ptr.md) access it directly:
+ both pages state, word for word, "No copies are made." -- at the cost of that reference or pointer becoming invalid
+ once the underlying value changes.
+- **Iterate by reference.** `#!cpp basic_json::iterator::operator*()` returns a `reference` (an alias for
+ `#!cpp basic_json&`), but a range-based for loop with a by-value loop variable (`#!cpp for (auto el : j)`) still
+ copies each element, because plain `#!cpp auto` drops the reference. Write `#!cpp for (const auto& el : j)` (or
+ `#!cpp auto&` for a mutable loop), and use [`items()`](../api/basic_json/items.md) the same way when the key is
+ needed too -- its own examples use `#!cpp for (auto& el : j.items())`.
+- **Construct in place.** [`emplace_back()`](../api/basic_json/emplace_back.md) (arrays, amortized constant time) and
+ [`emplace()`](../api/basic_json/emplace.md) (objects, logarithmic in the size of the container for `json`) forward
+ their arguments directly to a `basic_json` constructor, rather than requiring a temporary value to be
+ constructed and then copied or moved in. [`push_back()`](../api/basic_json/push_back.md) has an rvalue overload
+ (`#!cpp push_back(basic_json&&)`) for a value that already exists: `#!cpp j.push_back(std::move(value))` moves it
+ in instead of copying it.
+- **Skip the bounds check when it is redundant.** [`at()`](../api/basic_json/at.md) and
+ [`operator[]`](../api/basic_json/operator%5B%5D.md) have the same complexity (constant for a valid array index,
+ logarithmic for an object key in `json`) -- the difference is that `at()` additionally checks the key or index and
+ throws if it is invalid, while `operator[]` does not (see [unchecked access](element_access/unchecked_access.md) and
+ [checked access](element_access/checked_access.md)). Prefer `operator[]` when the surrounding code has already
+ established that the access is valid.
+- **Reserve array capacity.** `basic_json` has no public `reserve()`, but when building a large array
+ incrementally with a known final size, [`get_ref()`](../api/basic_json/get_ref.md) exposes the underlying
+ `#!cpp array_t` so it can be reserved directly -- see
+ ["reserving array capacity"](element_access/unchecked_access.md#performance-reserving-array-capacity) for the
+ one-line recipe.
+
+## Serialization
+
+[`dump()`](../api/basic_json/dump.md) with the default `#!cpp indent = -1` selects "the most compact representation"
+(word for word from the page); any non-negative `indent` pretty-prints instead, which is more readable but produces
+more bytes and more work. `dump()` builds and returns a complete `#!cpp string_t` containing the whole serialization.
+[`operator<<`](../api/operator_ltlt.md) writes directly to a `#!cpp std::ostream` instead, through the same
+serializer, but without ever materializing that intermediate string -- so if the destination is a stream (a file, or
+`#!cpp std::cout`), `#!cpp os << j;` avoids the allocation and copy that `#!cpp os << j.dump();` would incur for large
+values.
+
+## Diagnostics overhead
+
+Two opt-in macros add diagnostic information to exceptions and to every value, at a cost that is only worth paying
+while it is in use:
+
+- [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) adds a JSON Pointer to exception messages, pointing at the
+ value that triggered the exception. Quoting the page directly: "enabling this macro increases the size of every
+ JSON value by one pointer and adds some runtime overhead" -- every value gains a parent pointer that has to be kept
+ up to date as the document is built and modified.
+- [`JSON_DIAGNOSTIC_POSITIONS`](../api/macros/json_diagnostic_positions.md) adds
+ [`start_pos()`](../api/basic_json/start_pos.md) and [`end_pos()`](../api/basic_json/end_pos.md), the byte offsets a
+ value occupied in its parsed input. Quoting the page: "enabling this macro increases the size of every JSON value by
+ two `std::size_t` fields and adds slight runtime overhead to parsing, copying JSON value objects, and the generation
+ of error messages for exceptions."
+
+Both default to off. Enable them where better diagnostics are worth the overhead (for example, while validating
+untrusted input, or in a debug build), and keep them off in a release build that does not need them.
+
+## Compile time
+
+[``](../home/architecture.md#source-layout) forward-declares
+[`basic_json`](../api/basic_json/index.md), [`json`](../api/json.md), [`ordered_json`](../api/ordered_json.md),
+[`json_pointer`](../api/json_pointer/index.md), and [`adl_serializer`](../api/adl_serializer/index.md), pulling in only
+a handful of lightweight standard headers instead of the full `json.hpp`. A header that only needs to *name*
+`nlohmann::json` -- in a function signature or a class member declaration, for instance -- can include `json_fwd.hpp`
+and leave `#!cpp #include ` to the source files that actually parse, build, or serialize values,
+the same way a project would forward-declare any other heavy class to keep it out of widely-included headers:
+
+```cpp
+// my_type.hpp
+#include
+
+class my_type
+{
+ nlohmann::json config() const;
+};
+
+// my_type.cpp
+#include
+#include "my_type.hpp"
+
+nlohmann::json my_type::config() const { /* ... */ }
+```
+
+One caveat: ABI-affecting macros such as `JSON_DIAGNOSTICS` and `JSON_DIAGNOSTIC_POSITIONS` are encoded into the
+library's [inline namespace name](namespace.md#limitations). Every translation unit -- whether it includes
+`json_fwd.hpp` or the full header -- must define them the same way, or linking fails with undefined references
+instead of a compile error.
+
+If I/O support is not needed at all, [`JSON_NO_IO`](../api/macros/json_no_io.md) excludes ``, ``,
+``, ``, and `` outright and drops the `#!cpp std::istream`/`#!cpp FILE*` `parse` overloads and
+[`operator<<`](../api/operator_ltlt.md) that depend on them (`dump()` itself is unaffected, since it only returns a
+string); it exists for environments where those headers are unavailable (such as Intel SGX), and as a side effect
+those headers are then never processed by the compiler at all.
+
+## See also
+
+- [Design goals](../home/design_goals.md) - why this library does not optimize for speed first
+- [Architecture](../home/architecture.md) - how input adapters, the lexer, and the serializer fit together
+- [Parsing](parsing/index.md) - the available parsing functions and inputs
+- [SAX interface](parsing/sax_interface.md) - parse without building a DOM
+- [Binary formats](binary_formats/index.md) - compact alternatives to JSON text
+- [Object Order](object_order.md) - `json` vs. `ordered_json` and other `ObjectType` choices
+- [Template Parameter Requirements](types/template_parameters.md) - custom container and allocator types
+- [Supported macros](macros.md) - overview of all configuration macros, including the diagnostics ones above
diff --git a/docs/mkdocs/docs/features/serialization.md b/docs/mkdocs/docs/features/serialization.md
index 5b916e6c8..d9802bf08 100644
--- a/docs/mkdocs/docs/features/serialization.md
+++ b/docs/mkdocs/docs/features/serialization.md
@@ -28,7 +28,7 @@ std::cout << j << std::endl;
By default, `dump` produces the most compact representation without any superfluous whitespace. Passing a non-negative
`indent` argument pretty-prints the output with the given number of spaces per level:
-??? example
+??? example "Example: pretty-print JSON values with `dump()`"
```cpp
--8<-- "examples/dump.cpp"
@@ -65,7 +65,7 @@ serialization fails by default. The fourth argument of `dump` selects an
- `replace` — replace invalid bytes with the Unicode replacement character U+FFFD (`�`).
- `ignore` — silently drop invalid bytes.
-??? example
+??? example "Example: serialize invalid UTF-8 with different error handlers"
```cpp
--8<-- "examples/error_handler_t.cpp"
diff --git a/docs/mkdocs/docs/features/types/number_handling.md b/docs/mkdocs/docs/features/types/number_handling.md
index ac44ceee8..8bcf2ddb4 100644
--- a/docs/mkdocs/docs/features/types/number_handling.md
+++ b/docs/mkdocs/docs/features/types/number_handling.md
@@ -67,6 +67,17 @@ Positive integers are stored as `#!c std::uint64_t`, while negative integers are
distinction is determined at parse time: if the JSON number has a leading minus sign, it uses signed integer storage;
otherwise, it uses unsigned integer storage.
+```mermaid
+flowchart TD
+ A["number literal"] --> B{"has a fraction (.) or exponent (e/E)?"}
+ B -->|"yes"| F["number_float_t"]
+ B -->|"no"| C{"has a leading minus sign?"}
+ C -->|"yes"| D["try number_integer_t"]
+ C -->|"no"| E["try number_unsigned_t"]
+ D -->|"overflow"| F
+ E -->|"overflow"| F
+```
+
!!! info "Notes"
- Numbers with a decimal digit or scientific notation are always stored as `#!c double`.
@@ -77,7 +88,9 @@ otherwise, it uses unsigned integer storage.
[`std::strtold`](https://en.cppreference.com/w/cpp/string/byte/strtof). For that call, the library temporarily
replaces the `.` with the decimal point of the current locale (which may be longer than one byte, e.g., in
`fa_IR.UTF-8`), so the result does not depend on the locale either. Changing the locale in another thread during
- parsing is undefined behavior of the C library, though.
+ parsing is undefined behavior of the C library, though. Before version 3.13.0, the conversion was realized by
+ [`std::strtoull`](https://en.cppreference.com/w/cpp/string/byte/strtoul),
+ [`std::strtoll`](https://en.cppreference.com/w/cpp/string/byte/strtol), and `std::strtod`, respectively.
!!! example "Examples"
diff --git a/docs/mkdocs/docs/features/types/template_parameters.md b/docs/mkdocs/docs/features/types/template_parameters.md
index ea04dd09e..591d49ccd 100644
--- a/docs/mkdocs/docs/features/types/template_parameters.md
+++ b/docs/mkdocs/docs/features/types/template_parameters.md
@@ -214,7 +214,7 @@ The library does not sort or de-duplicate keys itself; the behavior described in
--8<-- "examples/custom_object_type.hpp"
```
-??? example "Compiling and using it"
+??? example "Example: use the custom `ObjectType`"
```cpp
--8<-- "examples/custom_object_type.cpp"
@@ -307,7 +307,7 @@ using array_t = ArrayType>;
--8<-- "examples/custom_array_type.hpp"
```
-??? example "Compiling and using it"
+??? example "Example: use the custom `ArrayType`"
```cpp
--8<-- "examples/custom_array_type.cpp"
@@ -349,16 +349,16 @@ using array_t = ArrayType>;
### Always required
- A member type `value_type` that is one byte wide and `char`-compatible. The library stores and processes UTF-8
- encoded `char` data and hands `data()` to `#!cpp std::strtoull`/`#!cpp std::strtoll`.
+ encoded `char` data and passes `data()` to functions that take a `#!cpp const char*`, such as `#!cpp std::strtod`.
`#!cpp std::wstring`, `#!cpp std::u16string`, and `#!cpp std::u32string` are **not** valid choices; see the FAQ on
[wide string handling](../../home/faq.md#wide-string-handling).
- Constructors: default, copy, move, from `#!cpp const char*` (which must not be `#!cpp explicit`), from
`#!cpp (const char*, size_type)`, and from `#!cpp (size_type, char)`; and copy or move assignment.
- Member functions `size()`, `clear()`, `resize(n, c)`, `data()`, `push_back(char)`, and `operator[]`
(const and non-const, returning references). `c_str()` and `back()` are **not** required.
-- `data()` must return a pointer to a contiguous, **null-terminated** buffer -- the parser hands it to
- `#!cpp std::strtoull`. A type whose `data()` is not null-terminated does not fail to compile; it silently
- misparses numbers.
+- `data()` must return a pointer to a contiguous, **null-terminated** buffer -- the parser may hand it to
+ `#!cpp std::strtod`, which reads up to the null character. A type whose `data()` is not null-terminated does not
+ fail to compile; it can silently misparse floating-point numbers.
- `append(const char*, size_type)`, used by [`dump`](../../api/basic_json/dump.md), and `append(const StringType&)`,
used by the CBOR reader for indefinite-length strings. The library's internal string concatenation additionally has
to append a `#!cpp char` and a `#!cpp const char*`; for each it selects between `append(arg)`, `#!cpp operator+=`,
@@ -395,6 +395,7 @@ using array_t = ArrayType>;
| [`to_bson`](../../api/basic_json/to_bson.md) | `find(value_type)` and `npos` |
| [`parse`](../../api/basic_json/parse.md) from a `string_t` | the input adapters must accept it; otherwise pass a character range |
| `#!cpp operator<<(std::ostream&, const json_pointer&)` | streamability to `#!cpp std::ostream` |
+| [`to_string`](../../api/basic_json/to_string.md) | conversion of `StringType` to `#!cpp std::string` (the function returns a `#!cpp std::string`) |
| exception messages | `data()` and `size()`, or `begin()` and `end()` |
### Compatible types
@@ -449,7 +450,7 @@ using array_t = ArrayType>;
--8<-- "examples/custom_string_type.hpp"
```
-??? example "Compiling and using it"
+??? example "Example: use the custom `StringType`"
```cpp
--8<-- "examples/custom_string_type.cpp"
@@ -672,7 +673,7 @@ such a container to a `basic_json` value.
--8<-- "examples/custom_binary_type.hpp"
```
-??? example "Compiling and using it"
+??? example "Example: use the custom `BinaryType`"
```cpp
--8<-- "examples/custom_binary_type.cpp"
diff --git a/docs/mkdocs/docs/home/customers.md b/docs/mkdocs/docs/home/customers.md
index 72802ff17..336cc55c8 100644
--- a/docs/mkdocs/docs/home/customers.md
+++ b/docs/mkdocs/docs/home/customers.md
@@ -3,7 +3,7 @@
The library is used in multiple projects, applications, operating systems, etc. The list below is not exhaustive, but
the result of an internet search. If you know further customers of the library, [please let me know](mailto:mail@nlohmann.me).
-[](../images/customers.png)
+[](../images/customers.png)
## Space Exploration
@@ -125,7 +125,7 @@ the result of an internet search. If you know further customers of the library,
- [**GitHub CodeQL**](https://github.com/github/codeql/blob/main/shared/cpp/Diagnostics.h), a code analysis tool used for identifying security vulnerabilities and bugs in software through semantic queries
- [**GoPro ngfx**](https://github.com/gopro/ngfx), a low-level graphics abstraction and profiling framework developed by GoPro
- [**gRPC**](https://github.com/grpc/grpc/blob/master/tools/artifact_gen/utils.h), a high-performance universal remote procedure call framework
-- [**Hex-Rays**](https://docs.hex-rays.com/user-guide/user-interface/licenses), a reverse engineering toolset for analyzing and decompiling binaries, primarily used for security research and vulnerability analysis
+- [**Hex-Rays**](https://docs.hex-rays.com/core/user-interface/concepts/licenses), a reverse engineering toolset for analyzing and decompiling binaries, primarily used for security research and vulnerability analysis
- [**ImHex**](https://github.com/WerWolv/ImHex), a hex editor designed for reverse engineering, providing advanced features for data analysis and manipulation
- [**Intel GITS**](https://github.com/intel/gits), a tool for capturing and replaying graphics API calls for debugging and performance analysis
- [**Intel GPA Framework**](https://intel.github.io/gpasdk-doc/src/licenses.html), a suite of cross-platform tools for capturing, analyzing, and optimizing graphics applications across different APIs
@@ -240,9 +240,9 @@ the result of an internet search. If you know further customers of the library,
- [**Manticore Search**](https://github.com/manticoresoftware/manticoresearch/blob/main/src/searchdhttpcompat.cpp), a database for search, offering full-text and vector queries
- [**Milvus**](https://github.com/milvus-io/milvus/blob/master/internal/core/src/query/PlanImpl.h), a cloud-native vector database built for embedding similarity search
- [**MongoDB**](https://github.com/mongodb/mongo/blob/master/src/mongo/replay/config_handler.cpp), a general-purpose document database
-- [**MySQL Connector/C++**](https://docs.oracle.com/cd/E17952_01/connector-cpp-9.1-license-com-en/license-opentelemetry-cpp-com.html), a C++ library for connecting and interacting with MySQL databases
-- [**MySQL NDB Cluster**](https://downloads.mysql.com/docs/licenses/cluster-9.0-com-en.pdf), a distributed database system that provides high availability and scalability for MySQL databases
-- [**MySQL Shell**](https://downloads.mysql.com/docs/licenses/mysql-shell-8.0-gpl-en.pdf), an advanced client and code editor for interacting with MySQL servers, supporting SQL, Python, and JavaScript
+- [**MySQL Connector/C++**](https://downloads.mysql.com/docs/licenses/connector-cpp-26.7-com-en.pdf), a C++ library for connecting and interacting with MySQL databases
+- [**MySQL NDB Cluster**](https://downloads.mysql.com/docs/licenses/cluster-26.7-com-en.pdf), a distributed database system that provides high availability and scalability for MySQL databases
+- [**MySQL Shell**](https://downloads.mysql.com/docs/licenses/mysql-shell-26.7-gpl-en.pdf), an advanced client and code editor for interacting with MySQL servers, supporting SQL, Python, and JavaScript
- [**PrestoDB**](https://github.com/prestodb/presto/blob/master/presto-native-execution/presto_cpp/main/Announcer.cpp), a distributed SQL query engine designed for large-scale data analytics, originally developed by Facebook
- [**ROOT Data Analysis Framework**](https://root.cern/doc/v614/classnlohmann_1_1basic__json.html), an open-source data analysis framework widely used in high-energy physics and other fields for data processing and visualization
- [**Typesense**](https://github.com/typesense/typesense/blob/v31/include/join.h), an open source typo-tolerant search engine
@@ -277,11 +277,11 @@ the result of an internet search. If you know further customers of the library,
- [**Acronis Cyber Protect Cloud**](https://care.acronis.com/s/article/59533-Third-party-software-used-in-Acronis-Cyber-Protect-Cloud?language=en_US), an all-in-one data protection solution that combines backup, disaster recovery, and cybersecurity to safeguard business data from threats like ransomware
- [**Baereos**](https://gitlab.tiger-computing.co.uk/packages/bareos/-/blob/tiger/bullseye/third-party/CLI11/examples/json.cpp), a backup solution that provides data protection and recovery options for various environments, including physical and virtual systems
-- [**Bitdefender Home Scanner**](https://www.bitdefender.de/site/Main/view/home-scanner-open-source.html), a tool from Bitdefender that scans devices for malware and security threats, providing a safeguard against potential online dangers
+- [**Bitdefender Home Scanner**](https://www.bitdefender.com/site/Main/view/home-scanner-open-source.html), a tool from Bitdefender that scans devices for malware and security threats, providing a safeguard against potential online dangers
- [**Cisco MLS++**](https://github.com/cisco/mlspp), an implementation of the Messaging Layer Security protocol for end-to-end encrypted group messaging
- [**Citrix Provisioning**](https://docs.citrix.com/en-us/provisioning/2203-ltsr/downloads/pvs-third-party-notices-2203.pdf), a solution that streamlines the delivery of virtual desktops and applications by allowing administrators to manage and provision resources efficiently across multiple environments
- [**Citrix Virtual Apps and Desktops**](https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/2305/downloads/third-party-notices-apps-and-desktops.pdf), a solution from Citrix that delivers virtual apps and desktops
-- [**Cyberarc**](https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf), a security solution that specializes in privileged access management, enabling organizations to control and monitor access to critical systems and data, thereby enhancing overall cybersecurity posture
+- [**CyberArk**](https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf), a security solution that specializes in privileged access management, enabling organizations to control and monitor access to critical systems and data, thereby enhancing overall cybersecurity posture
- [**Deutsche Telekom sysrepo-plugins**](https://github.com/telekom/sysrepo-plugins), a collection of YANG datastore plugins used to manage network devices
- [**Egnyte Desktop**](https://helpdesk.egnyte.com/hc/en-us/articles/360007071732-Third-Party-Software-Acknowledgements), a secure cloud storage solution designed for businesses, enabling file sharing, collaboration, and data management across teams while ensuring compliance and data protection
- [**Elster**](https://www.secunet.com/en/about-us/press/article/elstersecure-bietet-komfortablen-login-ohne-passwort-dank-secunet-protect4use), a digital platform developed by German tax authorities for secure and efficient electronic tax filing and management using secunet protect4use
diff --git a/docs/mkdocs/docs/home/exceptions.md b/docs/mkdocs/docs/home/exceptions.md
index d3c01a681..b57a9e846 100644
--- a/docs/mkdocs/docs/home/exceptions.md
+++ b/docs/mkdocs/docs/home/exceptions.md
@@ -41,7 +41,7 @@ Exceptions are used widely within the library. They can, however, be switched of
Note that [`JSON_THROW_USER`](../api/macros/json_throw_user.md) should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
-??? example
+??? example "Example: switch off exceptions and log errors before aborting"
The code below switches off exceptions and creates a log entry with a detailed error message in case of errors.
@@ -67,7 +67,7 @@ See [documentation of `JSON_TRY_USER`, `JSON_CATCH_USER` and `JSON_THROW_USER`](
Exceptions in the library are thrown in the local context of the JSON value they are detected. This makes detailed diagnostics messages, and hence debugging, difficult.
-??? example
+??? example "Example: standard diagnostic message"
```cpp
--8<-- "examples/diagnostics_standard.cpp"
@@ -85,7 +85,7 @@ To create better diagnostics messages, each JSON value needs a pointer to its pa
As this global context comes at the price of storing one additional pointer per JSON value and runtime overhead to maintain the parent relation, extended diagnostics are disabled by default. They can, however, be enabled by defining the preprocessor symbol [`JSON_DIAGNOSTICS`](../api/macros/json_diagnostics.md) to `1` before including `json.hpp`.
-??? example
+??? example "Example: extended diagnostic message with `JSON_DIAGNOSTICS`"
```cpp
--8<-- "examples/diagnostics_extended.cpp"
@@ -118,7 +118,7 @@ Exceptions have ids 1xx.
is the index of the terminating null byte or the end of file. This also
holds true when reading a byte vector (CBOR or MessagePack).
-??? example
+??? example "Example: catch a `parse_error` exception"
The following code shows how a `parse_error` exception can be caught.
@@ -395,7 +395,7 @@ the expected semantics.
Exceptions have ids 2xx.
-??? example
+??? example "Example: catch an `invalid_iterator` exception"
The following code shows how an `invalid_iterator` exception can be caught.
@@ -421,7 +421,7 @@ The iterators passed to constructor `basic_json(InputIT first, InputIT last)` ar
### json.exception.invalid_iterator.202
-In the [erase](../api/basic_json/erase.md) or insert function, the passed iterator `pos` does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
+In the [erase](../api/basic_json/erase.md) or [insert](../api/basic_json/insert.md) function, the passed iterator `pos` does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
!!! failure "Example messages"
@@ -454,7 +454,7 @@ When an iterator range for a primitive type (number, boolean, or string) is pass
### json.exception.invalid_iterator.205
-When an iterator for a primitive type (number, boolean, or string) is passed to an [erase](../api/basic_json/erase.md) function, the iterator has to be the `begin()` iterator, because it is the only way to address the stored value. All other iterators are invalid.
+When an iterator for a primitive type (number, boolean, or string) is passed to an [erase](../api/basic_json/erase.md) function, the iterator has to be the [`begin()`](../api/basic_json/begin.md) iterator, because it is the only way to address the stored value. All other iterators are invalid.
!!! failure "Example message"
@@ -545,7 +545,7 @@ The order of object iterators cannot be compared, because JSON objects are unord
### json.exception.invalid_iterator.214
-Cannot retrieve value from iterator: The iterator either refers to a null value, or it refers to a primitive type (number, boolean, or string), but does not match the iterator returned by `begin()`.
+Cannot retrieve value from iterator: The iterator either refers to a null value, or it refers to a primitive type (number, boolean, or string), but does not match the iterator returned by [`begin()`](../api/basic_json/begin.md).
!!! failure "Example message"
@@ -559,7 +559,7 @@ This exception is thrown in case of a type error; that is, a library function is
Exceptions have ids 3xx.
-??? example
+??? example "Example: catch a `type_error` exception"
The following code shows how a `type_error` exception can be caught.
@@ -611,7 +611,7 @@ To retrieve a reference to a value stored in a `basic_json` object with `get_ref
### json.exception.type_error.304
-The `at()` member functions can only be executed for certain JSON types.
+The [`at()`](../api/basic_json/at.md) member functions can only be executed for certain JSON types.
!!! failure "Example messages"
@@ -624,7 +624,7 @@ The `at()` member functions can only be executed for certain JSON types.
### json.exception.type_error.305
-The `operator[]` member functions can only be executed for certain JSON types.
+The [`operator[]`](../api/basic_json/operator%5B%5D.md) member functions can only be executed for certain JSON types.
!!! failure "Example messages"
@@ -637,7 +637,7 @@ The `operator[]` member functions can only be executed for certain JSON types.
### json.exception.type_error.306
-The `value()` member functions can only be executed for certain JSON types.
+The [`value()`](../api/basic_json/value.md) member functions can only be executed for certain JSON types.
!!! failure "Example message"
@@ -657,7 +657,7 @@ The [`erase()`](../api/basic_json/erase.md) member functions can only be execute
### json.exception.type_error.308
-The `push_back()` and `operator+=` member functions can only be executed for certain JSON types.
+The [`push_back()`](../api/basic_json/push_back.md) and [`operator+=`](../api/basic_json/operator+=.md) member functions can only be executed for certain JSON types.
!!! failure "Example message"
@@ -667,7 +667,7 @@ The `push_back()` and `operator+=` member functions can only be executed for cer
### json.exception.type_error.309
-The `insert()` member functions can only be executed for certain JSON types.
+The [`insert()`](../api/basic_json/insert.md) member functions can only be executed for certain JSON types.
!!! failure "Example messages"
@@ -680,7 +680,7 @@ The `insert()` member functions can only be executed for certain JSON types.
### json.exception.type_error.310
-The `swap()` member functions can only be executed for certain JSON types.
+The [`swap()`](../api/basic_json/swap.md) member functions can only be executed for certain JSON types.
!!! failure "Example message"
@@ -690,7 +690,7 @@ The `swap()` member functions can only be executed for certain JSON types.
### json.exception.type_error.311
-The `emplace()` and `emplace_back()` member functions can only be executed for certain JSON types.
+The [`emplace()`](../api/basic_json/emplace.md) and [`emplace_back()`](../api/basic_json/emplace_back.md) member functions can only be executed for certain JSON types.
!!! failure "Example messages"
@@ -703,7 +703,7 @@ The `emplace()` and `emplace_back()` member functions can only be executed for c
### json.exception.type_error.312
-The `update()` member functions can only be executed for certain JSON types.
+The [`update()`](../api/basic_json/update.md) member functions can only be executed for certain JSON types.
!!! failure "Example message"
@@ -713,7 +713,7 @@ The `update()` member functions can only be executed for certain JSON types.
### json.exception.type_error.313
-The `unflatten` function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well-defined.
+The [`unflatten()`](../api/basic_json/unflatten.md) function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well-defined.
!!! failure "Example message"
@@ -723,7 +723,7 @@ The `unflatten` function converts an object whose keys are JSON Pointers back in
### json.exception.type_error.314
-The `unflatten` function only works for an object whose keys are JSON Pointers.
+The [`unflatten()`](../api/basic_json/unflatten.md) function only works for an object whose keys are JSON Pointers.
!!! failure "Example message"
@@ -735,7 +735,7 @@ The `unflatten` function only works for an object whose keys are JSON Pointers.
### json.exception.type_error.315
-The `unflatten()` function only works for an object whose keys are JSON Pointers and whose values are primitive.
+The [`unflatten()`](../api/basic_json/unflatten.md) function only works for an object whose keys are JSON Pointers and whose values are primitive.
!!! failure "Example message"
@@ -747,7 +747,7 @@ The `unflatten()` function only works for an object whose keys are JSON Pointers
### json.exception.type_error.316
-The `dump()` function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded.
+The [`dump()`](../api/basic_json/dump.md) function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. See the FAQ entry on [serializing untrusted or invalid UTF-8](faq.md#serializing-untrusted-or-invalid-utf-8) for background and the recommended fix.
!!! failure "Example message"
@@ -788,7 +788,7 @@ This exception is thrown in case a library function is called on an input parame
Exceptions have ids 4xx.
-??? example
+??? example "Example: catch an `out_of_range` exception"
The following code shows how an `out_of_range` exception can be caught.
@@ -1026,7 +1026,7 @@ other exception types.
Exceptions have ids 5xx.
-??? example
+??? example "Example: catch an `other_error` exception"
The following code shows how an `other_error` exception can be caught.
diff --git a/docs/mkdocs/docs/home/faq.md b/docs/mkdocs/docs/home/faq.md
index 8b3602bd1..ca113004c 100644
--- a/docs/mkdocs/docs/home/faq.md
+++ b/docs/mkdocs/docs/home/faq.md
@@ -44,9 +44,9 @@ for objects.
json j = json::array({true}); // [true]
```
-**Opt-in copy semantics (since version 3.12.0)**
+**Opt-in copy semantics (since version 3.13.0)**
-If you define `JSON_BRACE_INIT_COPY_SEMANTICS` to `1` before including the library, single-element brace initialization is treated as copy/move instead of creating a single-element array:
+If you define [`JSON_BRACE_INIT_COPY_SEMANTICS`](../api/macros/json_brace_init_copy_semantics.md) to `1` before including the library, single-element brace initialization is treated as copy/move instead of creating a single-element array:
```cpp
#define JSON_BRACE_INIT_COPY_SEMANTICS 1
@@ -85,7 +85,7 @@ The library supports **Unicode input** as follows:
- The library will not replace [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1).
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
-- When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
+- When you store strings with different encodings in the library, calling [`dump()`](../api/basic_json/dump.md) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.
In most cases, the parser is right to complain, because the input is not UTF-8 encoded. This is especially true for Microsoft Windows, where Latin-1 or ISO 8859-1 is often the standard encoding.
@@ -94,7 +94,7 @@ In most cases, the parser is right to complain, because the input is not UTF-8 e
!!! question "Questions"
- - Why does `json::parse()` silently ignore part of my input?
+ - Why does [`json::parse()`](../api/basic_json/parse.md) silently ignore part of my input?
- Why does a `std::string`/buffer with extra data after the JSON text parse without error, while a similar-looking string with extra text does not?
A `'\0'` (NUL) byte anywhere in the input is treated the same as the real end of the input, rather than as an ordinary (and, outside of a string, invalid) byte. Everything from that byte onward is silently ignored, without a parse error — including further, otherwise well-formed JSON:
@@ -197,8 +197,8 @@ same object -- is a data race and requires external synchronization (e.g., a `st
Does this library support JSON Schema validation?
Not directly, but the companion project [json-schema-validator](https://github.com/pboettch/json-schema-validator)
-builds JSON Schema (draft 4, 6, 7, and 2019-09) validation on top of this library and is a common recommendation
-for this use case.
+builds JSON Schema (draft 7; draft 4 in its older, now-superseded 1.x releases) validation on top of this library
+and is a common recommendation for this use case.
## Exceptions
@@ -296,15 +296,13 @@ If you get ambiguous-overload errors when passing a JSON value to `fmt::format`/
Why does the code not compile with Android SDK?
-Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.
+Since [NDK r18](https://github.com/android/ndk/wiki/Changelog-r18) (2018), GCC and the `gnustl`/`stlport` C++
+libraries have been removed from the Android NDK; Clang and `libc++` are now the only compiler and C++ library, and
+they support C++11 and later out of the box. With a current NDK, no special configuration is needed to use this
+library.
-```ini
-APP_STL := c++_shared
-NDK_TOOLCHAIN_VERSION := clang3.6
-APP_CPPFLAGS += -frtti -fexceptions
-```
-
-The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.
+Only very old NDKs (before r18), which defaulted to GCC and `gnustl`, lacked C++11 library features such as
+`std::to_string`. If you run into this, update to a current NDK.
### Missing STL function
@@ -314,4 +312,6 @@ The code compiles successfully with [Android NDK](https://developer.android.com/
- Why do I get a compilation error `'to_string' is not a member of 'std'` (or similarly, for `strtod` or `strtof`)?
- Why does the code not compile with MinGW or Android SDK?
-This is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).
+This is not an issue with the code, but rather with the compiler itself. On Android, use a current NDK (see above).
+For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and
+[this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug.
diff --git a/docs/mkdocs/docs/home/license.md b/docs/mkdocs/docs/home/license.md
index 98831cc08..6e0a1cd23 100644
--- a/docs/mkdocs/docs/home/license.md
+++ b/docs/mkdocs/docs/home/license.md
@@ -1,6 +1,6 @@
# License
-
+
The class is licensed under the [MIT License](https://opensource.org/licenses/MIT):
diff --git a/docs/mkdocs/docs/home/releases.md b/docs/mkdocs/docs/home/releases.md
index cdaca4c0d..f91f82dda 100644
--- a/docs/mkdocs/docs/home/releases.md
+++ b/docs/mkdocs/docs/home/releases.md
@@ -4,6 +4,11 @@ This page summarizes the notable changes of every release and links to the relev
The **complete release notes** — including all changes, the download files, and their checksums — are
published on the [GitHub releases page](https://github.com/nlohmann/json/releases).
+!!! info "Unreleased changes"
+
+ This documentation is built from the `develop` branch and may describe changes that are not part of a release
+ yet. Their version numbers are followed by an unreleased badge.
+
## v3.12.0 (2025-04-11)
Fixes bugs found in 3.11.3 and adds several features. All changes are backward-compatible.
diff --git a/docs/mkdocs/docs/home/sponsors.md b/docs/mkdocs/docs/home/sponsors.md
index 6c3a558fb..ddbfbf3f0 100644
--- a/docs/mkdocs/docs/home/sponsors.md
+++ b/docs/mkdocs/docs/home/sponsors.md
@@ -9,7 +9,7 @@ You can sponsor this library at [GitHub Sponsors](https://github.com/sponsors/nl
## Named Sponsors
-- [Michael Hartmann](https://github.com/reFX-Mike)
+- Michael Hartmann
- [Stefan Hagen](https://github.com/sthagen)
- [Steve Sperandeo](https://github.com/homer6)
- [Robert Jefe Lindstädt](https://github.com/eljefedelrodeodeljefe)
diff --git a/docs/mkdocs/docs/index.md b/docs/mkdocs/docs/index.md
index 0e49c836c..091eca5e8 100644
--- a/docs/mkdocs/docs/index.md
+++ b/docs/mkdocs/docs/index.md
@@ -1,3 +1,114 @@
# JSON for Modern C++
-
+
+
+JSON for Modern C++ is a header-only C++11 library that turns JSON into a first-class C++ data type, using the operator
+magic of modern C++ so that creating, reading, and modifying JSON values feels as natural as it does in languages like
+Python. The whole library is available as a single header, `json.hpp`, with no dependencies, no subproject, and no
+complex build system to set up; a companion header, `json_fwd.hpp`, provides forward declarations to keep compile times
+down. See [header-only integration](integration/index.md) for details. It is heavily unit-tested with 100% code
+coverage, checked with Valgrind and the Clang Sanitizers for memory leaks, and continuously fuzz-tested by Google
+OSS-Fuzz.
+
+## Quick start
+
+Add the single header to your project and use the library like this:
+
+```cpp
+#include
+#include
+
+using json = nlohmann::json;
+
+int main()
+{
+ // parse a JSON string
+ json j = json::parse(R"({"happy": true, "pi": 3.141})");
+
+ // access and modify values
+ j["name"] = "Niels";
+ j["list"] = {1, 0, 2};
+
+ // serialize with an indent of 4 spaces
+ std::cout << j.dump(4) << '\n';
+}
+```
+
+Get the library by copying the single header [`json.hpp`](https://github.com/nlohmann/json/releases) from the
+releases page into a directory `nlohmann` on your include path, or by installing it with a package manager:
+
+```sh
+brew install nlohmann-json # Homebrew
+vcpkg install nlohmann-json # vcpkg
+```
+
+```cmake
+find_package(nlohmann_json 3.12.0 REQUIRED)
+target_link_libraries(myproject PRIVATE nlohmann_json::nlohmann_json)
+```
+
+See [Integration](integration/index.md) for CMake in detail, all supported package managers (Conan, Meson, Bazel,
+Conda, and more), and pkg-config.
+
+## Explore the documentation
+
+
+
+- :octicons-rocket-24:{ .lg .middle } __Features__
+
+ ---
+
+ Creating, parsing, accessing, and serializing JSON values, JSON Pointer/Patch, binary formats, and more.
+
+ [:octicons-arrow-right-24: Features](features/index.md)
+
+- :octicons-package-24:{ .lg .middle } __Integration__
+
+ ---
+
+ Add the library to your project via a single header, CMake, a package manager, or pkg-config.
+
+ [:octicons-arrow-right-24: Integration](integration/index.md)
+
+- :octicons-book-24:{ .lg .middle } __API documentation__
+
+ ---
+
+ The complete reference for `basic_json` and its member functions, types, and related classes.
+
+ [:octicons-arrow-right-24: API documentation](api/basic_json/index.md)
+
+- :octicons-question-24:{ .lg .middle } __FAQ__
+
+ ---
+
+ Answers to common questions and known surprises when using the library.
+
+ [:octicons-arrow-right-24: FAQ](home/faq.md)
+
+- :octicons-tag-24:{ .lg .middle } __Releases__
+
+ ---
+
+ What changed in each release, with links to the relevant documentation.
+
+ [:octicons-arrow-right-24: Releases](home/releases.md)
+
+- :octicons-people-24:{ .lg .middle } __Community__
+
+ ---
+
+ The ecosystem, contribution guidelines, governance, and quality assurance around the project.
+
+ [:octicons-arrow-right-24: Community](community/index.md)
+
+
+
+!!! info "Unreleased changes"
+
+ This documentation is built from the `develop` branch and may describe changes that are not part of a release
+ yet. Their version numbers are followed by an unreleased badge; see
+ [Releases](home/releases.md) for what shipped in each version.
+
+The library is licensed under the [MIT License](home/license.md). The source code, issue tracker, and discussions
+are on [GitHub](https://github.com/nlohmann/json).
diff --git a/docs/mkdocs/docs/integration/bazel/MODULE.bazel b/docs/mkdocs/docs/integration/bazel/MODULE.bazel
index ba902be27..5d43f9b90 100644
--- a/docs/mkdocs/docs/integration/bazel/MODULE.bazel
+++ b/docs/mkdocs/docs/integration/bazel/MODULE.bazel
@@ -1 +1 @@
-bazel_dep(name = "nlohmann_json", version = "3.11.3.bcr.1")
+bazel_dep(name = "nlohmann_json", version = "3.12.0.bcr.2")
diff --git a/docs/mkdocs/docs/integration/cmake.md b/docs/mkdocs/docs/integration/cmake.md
index 4160584d5..785fc3ed6 100644
--- a/docs/mkdocs/docs/integration/cmake.md
+++ b/docs/mkdocs/docs/integration/cmake.md
@@ -5,7 +5,8 @@
You can use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage
requirements for [`INTERFACE_INCLUDE_DIRECTORIES`](https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES.html)
to point to the appropriate include directories and [`INTERFACE_COMPILE_FEATURES`](https://cmake.org/cmake/help/latest/prop_tgt/INTERFACE_COMPILE_FEATURES.html)
-for the necessary C++11 flags.
+for the necessary C++11 flags. Most [package managers](package_managers.md) that provide a CMake package configuration
+for this library expose this same target.
### External
@@ -138,7 +139,7 @@ Enable [extended diagnostic messages](../home/exceptions.md#extended-diagnostic-
!!! warning "Does not apply to a pre-installed package"
This option only takes effect when building nlohmann/json from source as part of your own
- CMake project (e.g. via [`FetchContent`](#fetchcontent) or [`add_subdirectory`](#external)).
+ CMake project (e.g. via [`FetchContent`](#fetchcontent) or [`add_subdirectory`](#embedded)).
It has **no effect** on a package that was already built and installed elsewhere (Homebrew,
vcpkg, a system package, etc.) — the resulting compile definition is baked into the exported
`nlohmann_jsonTargets.cmake` at install time, and `set(JSON_Diagnostics ON)` before
@@ -182,15 +183,22 @@ Skip expensive/slow test suites. This option is `OFF` by default. Depends on `JS
### `JSON_GlobalUDLs`
Place user-defined string literals in the global namespace by defining the macro
-[`JSON_USE_GLOBAL_UDLS`](../api/macros/json_use_global_udls.md). This option is `OFF` by default.
+[`JSON_USE_GLOBAL_UDLS`](../api/macros/json_use_global_udls.md). This option is `ON` by default; see the
+[migration guide](migration_guide.md#import-namespace-literals-for-udls) for how to prepare code for the next major
+release, where the literals are removed from the global namespace.
### `JSON_ImplicitConversions`
-Enable implicit conversions by defining macro [`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md). This option is `ON` by default.
+Enable implicit conversions by defining macro
+[`JSON_USE_IMPLICIT_CONVERSIONS`](../api/macros/json_use_implicit_conversions.md). This option is `ON` by default; see
+the [migration guide](migration_guide.md#replace-implicit-conversions) for how to prepare code for the next major
+release, where implicit conversions are switched off by default.
### `JSON_Install`
-Install CMake targets during install step. This option is `ON` by default if the library's CMake project is the top project.
+Install CMake targets during install step. This option is `ON` by default if the library's CMake project is the top
+project. Installing also generates a [pkg-config](pkg-config.md) file for tools that rely on `pkg-config` instead of
+CMake.
### `JSON_LegacyDiscardedValueComparison`
@@ -209,6 +217,13 @@ Treat the library headers like system headers (i.e., adding `SYSTEM` to the [`ta
Reject a `'\0'` (NUL) byte in the input instead of treating it as end of input, by defining the macro
[`JSON_STRICT_NUL_HANDLING`](../api/macros/json_strict_nul_handling.md). This option is `OFF` by default.
+### `JSON_TestSimdutf`
+
+Build the unit tests against the [simdutf](https://github.com/simdutf/simdutf) UTF-8 validation backend by defining
+[`JSON_USE_SIMDUTF`](../api/macros/json_use_simdutf.md) for every test target. simdutf is fetched during configuration;
+its version is set by the cache variable `JSON_SIMDUTF_VERSION`. This option is `OFF` by default. Depends on
+`JSON_BuildTests`.
+
### `JSON_Valgrind`
Execute the test suite with [Valgrind](https://valgrind.org). This option is `OFF` by default. Depends on `JSON_BuildTests`.
diff --git a/docs/mkdocs/docs/integration/index.md b/docs/mkdocs/docs/integration/index.md
index 86ea131f8..155001a28 100644
--- a/docs/mkdocs/docs/integration/index.md
+++ b/docs/mkdocs/docs/integration/index.md
@@ -1,4 +1,34 @@
-# Header only
+# Integration
+
+There are several ways to add this header-only library to a C++ project. The following flowchart summarizes how to
+pick one:
+
+```mermaid
+flowchart TD
+ A[Add the library to a C++ project] --> B{Already using CMake?}
+ B -- no --> C{Using pkg-config or plain Makefiles?}
+ C -- yes --> D[pkg-config]
+ C -- no --> E[Copy the single header]
+ B -- yes --> F{Library installed system-wide?}
+ F -- yes --> G["find_package()"]
+ F -- no --> H{Use a package manager?}
+ H -- yes --> I[Package manager]
+ H -- no --> J["add_subdirectory() or FetchContent"]
+```
+
+- **Copy the single header**, as described [below](#header-only) — no build-system integration required.
+- **CMake**: use [`find_package()`](cmake.md#external) if the library is already installed,
+ [`add_subdirectory()`](cmake.md#embedded) to embed the source tree, or [`FetchContent`](cmake.md#fetchcontent) to
+ download it at configure time; see [CMake](cmake.md).
+- **Package managers**: install the library with a package manager such as Homebrew, Conan, or vcpkg; see
+ [Package Managers](package_managers.md).
+- **pkg-config**: if you use bare Makefiles instead of CMake, [pkg-config](pkg-config.md) can supply the include flags
+ for an already-installed library.
+
+Once the library is integrated, see the [Migration Guide](migration_guide.md) for how to keep your code future-proof
+across releases.
+
+## Header only
[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required
file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add
diff --git a/docs/mkdocs/docs/integration/migration_guide.md b/docs/mkdocs/docs/integration/migration_guide.md
index 8b718d969..29d54b6df 100644
--- a/docs/mkdocs/docs/integration/migration_guide.md
+++ b/docs/mkdocs/docs/integration/migration_guide.md
@@ -1,6 +1,8 @@
# Migration Guide
-This page collects some guidelines on how to future-proof your code for future versions of this library.
+This page collects some guidelines on how to future-proof your code for future versions of this library. For how to
+add the library to your project in the first place, see [Integration](index.md), [CMake](cmake.md), or
+[Package Managers](package_managers.md).
## Replace deprecated functions
@@ -9,7 +11,7 @@ deprecations are annotated with
[`HEDLEY_DEPRECATED_FOR`](https://nemequ.github.io/hedley/api-reference.html#HEDLEY_DEPRECATED_FOR) to report which
function to use instead.
-#### Parsing
+### Parsing
- Function `friend std::istream& operator<<(basic_json&, std::istream&)` is deprecated since 3.0.0. Please use
[`friend std::istream& operator>>(std::istream&, basic_json&)`](../api/operator_gtgt.md) instead.
@@ -33,9 +35,11 @@ function to use instead.
- Passing iterator pairs or pointer/length pairs to parsing functions ([`parse`](../api/basic_json/parse.md),
[`accept`](../api/basic_json/accept.md), [`sax_parse`](../api/basic_json/sax_parse.md),
[`from_cbor`](../api/basic_json/from_cbor.md), [`from_msgpack`](../api/basic_json/from_msgpack.md),
- [`from_ubjson`](../api/basic_json/from_ubjson.md), and [`from_bson`](../api/basic_json/from_bson.md) via initializer
+ [`from_ubjson`](../api/basic_json/from_ubjson.md), and [`from_bson`](../api/basic_json/from_bson.md)) via initializer
lists is deprecated since 3.8.0. Instead, pass two iterators; for instance, call `from_cbor(ptr, ptr+len)` instead of
- `from_cbor({ptr, len})`.
+ `from_cbor({ptr, len})`. Likewise, passing a pointer and a length as two separate arguments to `from_cbor`,
+ `from_msgpack`, `from_ubjson`, and `from_bson` is deprecated since 3.8.0; call `from_cbor(ptr, ptr+len)` instead of
+ `from_cbor(ptr, len)`.
=== "Deprecated"
@@ -51,7 +55,7 @@ function to use instead.
bool ok = nlohmann::json::accept(s, s + std::strlen(s));
```
-#### JSON Pointers
+### JSON Pointers
- Comparing JSON Pointers with strings via [`operator==`](../api/json_pointer/operator_eq.md) and
[`operator!=`](../api/json_pointer/operator_ne.md) is deprecated since 3.11.2. To compare a
@@ -93,7 +97,9 @@ function to use instead.
- Passing a `basic_json` specialization as template parameter `RefStringType` to
[`json_pointer`](../api/json_pointer/index.md) is deprecated since 3.11.0. The string type can now be directly
- provided.
+ provided. This also applies to passing such a JSON pointer to [`at`](../api/basic_json/at.md),
+ [`contains`](../api/basic_json/contains.md), [`operator[]`](../api/basic_json/operator%5B%5D.md), and
+ [`value`](../api/basic_json/value.md).
=== "Deprecated"
@@ -108,10 +114,11 @@ function to use instead.
nlohmann::json_pointer ptr("/foo/bar/1");
```
- Thereby, `nlohmann::my_json::json_pointer` is an alias for `nlohmann::json_pointer` and is always an
- alias to the `json_pointer` with the appropriate string type for all specializations of `basic_json`.
+ Thereby, `my_json::json_pointer` is an alias for `nlohmann::json_pointer`; in general,
+ `basic_json::json_pointer` is always an alias to the `json_pointer` with the appropriate string type for all
+ specializations of `basic_json`.
-#### Miscellaneous functions
+### Miscellaneous functions
- The function `iterator_wrapper` is deprecated since 3.1.0. Please use the member function
[`items`](../api/basic_json/items.md) instead.
@@ -260,7 +267,7 @@ exact version and configuration is relevant, use macro
}
```
-## Do not use the `details` namespace
+## Do not use the `detail` namespace
-The `details` namespace is not part of the public API of the library and can change in any version without an
-announcement. Do not rely on any function or type in the `details` namespace.
+The `nlohmann::detail` namespace is not part of the public API of the library and can change in any version without
+an announcement. Do not rely on any function or type in the `detail` namespace.
diff --git a/docs/mkdocs/docs/integration/msys2/example.cpp b/docs/mkdocs/docs/integration/msys2/example.cpp
new file mode 100644
index 000000000..1a7ac4de2
--- /dev/null
+++ b/docs/mkdocs/docs/integration/msys2/example.cpp
@@ -0,0 +1,10 @@
+#include
+#include
+#include
+
+using json = nlohmann::json;
+
+int main()
+{
+ std::cout << std::setw(4) << json::meta() << std::endl;
+}
diff --git a/docs/mkdocs/docs/integration/nuget/nuget-package-content.png b/docs/mkdocs/docs/integration/nuget/nuget-package-content.png
deleted file mode 100644
index cc975b98b..000000000
Binary files a/docs/mkdocs/docs/integration/nuget/nuget-package-content.png and /dev/null differ
diff --git a/docs/mkdocs/docs/integration/nuget/nuget-project-changes.png b/docs/mkdocs/docs/integration/nuget/nuget-project-changes.png
deleted file mode 100644
index eb2a520a8..000000000
Binary files a/docs/mkdocs/docs/integration/nuget/nuget-project-changes.png and /dev/null differ
diff --git a/docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png b/docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png
deleted file mode 100644
index 74657f264..000000000
Binary files a/docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png and /dev/null differ
diff --git a/docs/mkdocs/docs/integration/package_managers.md b/docs/mkdocs/docs/integration/package_managers.md
index 28f95e584..d5357b8ff 100644
--- a/docs/mkdocs/docs/integration/package_managers.md
+++ b/docs/mkdocs/docs/integration/package_managers.md
@@ -31,13 +31,17 @@ When executed, this program should create output similar to
--8<-- "examples/meta.output"
```
+Many of the package managers below install a CMake package configuration that exposes the same
+`nlohmann_json::nlohmann_json` interface target described in [CMake](cmake.md); their CMake examples below link
+against that target.
+
## Homebrew
!!! abstract "Summary"
formula: [**`nlohmann-json`**](https://formulae.brew.sh/formula/nlohmann-json)
- - [](https://repology.org/project/nlohmann-json/versions)
+ - [](https://formulae.brew.sh/formula/nlohmann-json)
- :octicons-tag-24: Available versions: current version and development version (with `--HEAD` parameter)
- :octicons-rocket-24: The formula is updated with every release.
- :octicons-person-24: Maintainer: Niels Lohmann
@@ -121,8 +125,8 @@ meson wrap install nlohmann_json
Please see the Meson project for any issues regarding the packaging.
The provided `meson.build` can also be used as an alternative to CMake for installing `nlohmann_json` system-wide in
-which case a pkg-config file is installed. To use it, have your build system require the `nlohmann_json`
-pkg-config dependency. In Meson, it is preferred to use the
+which case a [pkg-config](pkg-config.md) file is installed. To use it, have your build system require the
+`nlohmann_json` pkg-config dependency. In Meson, it is preferred to use the
[`dependency()`](https://mesonbuild.com/Reference-manual.html#dependency) object with a subproject fallback, rather than
using the subproject directly.
@@ -165,7 +169,7 @@ using the subproject directly.
This repository provides a [Bazel](https://bazel.build/) `MODULE.bazel` and a corresponding `BUILD.bazel` file. Therefore, this
repository can be referenced within a `MODULE.bazel` by rules such as `archive_override`, `git_override`, or `local_path_override`. To use the library, you need to depend on the target `@nlohmann_json//:json` (i.e., via `deps` attribute).
-??? example
+??? example "Example: Bazel module with `bazel_dep`"
1. Create the following files:
@@ -173,7 +177,7 @@ repository can be referenced within a `MODULE.bazel` by rules such as `archive_o
--8<-- "integration/bazel/BUILD"
```
- ```ini title="WORKSPACE"
+ ```ini title="MODULE.bazel"
--8<-- "integration/bazel/MODULE.bazel"
```
@@ -194,7 +198,7 @@ repository can be referenced within a `MODULE.bazel` by rules such as `archive_o
recipe: [**`nlohmann_json`**](https://conan.io/center/recipes/nlohmann_json)
- - [](https://repology.org/project/nlohmann-json/versions)
+ - [](https://conan.io/center/recipes/nlohmann_json)
- :octicons-tag-24: Available versions: current version and older versions (see
[Conan Center](https://conan.io/center/recipes/nlohmann_json))
- :octicons-rocket-24: The package is updated automatically via
@@ -205,7 +209,7 @@ repository can be referenced within a `MODULE.bazel` by rules such as `archive_o
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nlohmann_json/x.y.z` to your `conanfile`'s
requires, where `x.y.z` is the release version you want to use.
-??? example
+??? example "Example: CMake with the Conan toolchain"
1. Create the following files:
@@ -240,7 +244,7 @@ requires, where `x.y.z` is the release version you want to use.
package: [**`nlohmann-json`**](https://packages.spack.io/package.html?name=nlohmann-json)
- - [](https://repology.org/project/nlohmann-json/versions)
+ - [](https://packages.spack.io/package.html?name=nlohmann-json)
- :octicons-tag-24: Available versions: current version and older versions (see
[Spack package](https://packages.spack.io/package.html?name=nlohmann-json))
- :octicons-rocket-24: The package is updated with every release.
@@ -257,7 +261,7 @@ spack install nlohmann-json
Please see the [Spack project](https://github.com/spack/spack) for any issues regarding the packaging.
-??? example
+??? example "Example: CMake with a Spack-installed package"
1. Create the following files:
@@ -309,7 +313,7 @@ hunter_add_package(nlohmann_json)
Please see the Hunter project for any issues regarding the packaging.
-??? example
+??? example "Example: CMake with HunterGate"
1. Create the following files:
@@ -341,7 +345,7 @@ Please see the Hunter project for any issues regarding the packaging.
package: [**`nlohmann-json`**](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json)
- - [](https://repology.org/project/nlohmann-json/versions)
+ - [](https://vcpkg.io/en/package/nlohmann-json)
- :octicons-tag-24: Available versions: current version
- :octicons-rocket-24: The package is updated with every release.
- :octicons-file-24: File issues at the [vcpkg issue tracker](https://github.com/microsoft/vcpkg/issues)
@@ -356,7 +360,7 @@ vcpkg install nlohmann-json
and follow the then displayed descriptions. Please see the vcpkg project for any issues regarding the packaging.
-??? example
+??? example "Example: CMake with the vcpkg toolchain"
1. Create the following files:
@@ -401,16 +405,16 @@ cget install nlohmann/json
A specific version can be installed with `cget install nlohmann/json@v3.12.0`. Also, the multiple header version can be
installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).
-??? example
+??? example "Example: CMake with the cget toolchain"
1. Create the following files:
```cmake title="CMakeLists.txt"
- --8<-- "integration/vcpkg/CMakeLists.txt"
+ --8<-- "integration/cget/CMakeLists.txt"
```
```cpp title="example.cpp"
- --8<-- "integration/vcpkg/example.cpp"
+ --8<-- "integration/cget/example.cpp"
```
2. Initialize cget
@@ -443,6 +447,58 @@ installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nl
- :octicons-file-24: File issues at the [library issue tracker](https://github.com/nlohmann/json/issues)
- :octicons-question-24: [Xcode documentation](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app)
+If you are using the [Swift Package Manager](https://www.swift.org/documentation/package-manager/), add this
+repository as a package dependency and depend on its `json` product:
+
+```swift
+dependencies: [
+ .package(url: "https://github.com/nlohmann/json", from: "3.12.0")
+],
+targets: [
+ .target(name: "MyTarget", dependencies: [.product(name: "json", package: "json")])
+]
+```
+
+The library's own [`Package.swift`](https://github.com/nlohmann/json/blob/develop/Package.swift) publishes
+`single_include/nlohmann` (not `single_include`) as the public headers directory, so include the header without the
+`nlohmann/` prefix:
+
+```cpp
+#include
+```
+
+??? example "Example: a minimal executable package"
+
+ 1. Create the following files (the source file goes into `Sources/json_example/`, following Swift Package
+ Manager's directory layout convention):
+
+ ```swift title="Package.swift"
+ --8<-- "integration/swift/Package.swift"
+ ```
+
+ ```cpp title="Sources/json_example/example.cpp"
+ --8<-- "integration/swift/example.cpp"
+ ```
+
+ 2. Build and run:
+
+ ```shell
+ swift run --build-system native
+ ```
+
+!!! warning
+
+ On some toolchains, `swift run`/`swift build` fail to link an **executable** target against the header-only
+ `json` product with an error such as `Build input file cannot be found: '.../json.o'`, because the product
+ itself has no compiled sources; see [#4650](https://github.com/nlohmann/json/issues/4650) and the upstream
+ [Swift Package Manager issue](https://github.com/swiftlang/swift-package-manager/issues/5706). Passing
+ `--build-system native` (shown above) selects Swift Package Manager's legacy build system, which does not
+ have this problem; depending on the library from a *library* target instead of an executable is not affected
+ either.
+
+You can also add the dependency from within Xcode via **File → Add Package Dependencies…** and the same repository
+URL; see [Apple's documentation](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app).
+
## NuGet
!!! abstract "Summary"
@@ -462,119 +518,28 @@ with
dotnet add package nlohmann.json
```
-??? example
+NuGet integrates with C++ projects through MSBuild, so it is mainly useful for Visual Studio/MSBuild projects; using
+it as a dependency from other build systems, such as CMake, is possible but more cumbersome than the other package
+managers on this page.
- Probably the easiest way to use NuGet packages is through Visual Studio graphical interface. Right-click on a
- project (any C++ project would do) in “Solution Explorer” and select “Manage NuGet Packages…”
+??? example "Example: Visual Studio project"
- 
+ 1. Right-click the project (any C++ project) in "Solution Explorer" and select "Manage NuGet Packages…"
- Now you can click on “Browse” tab and find the package you like to install.
+ 
- 
+ 2. Switch to the "Browse" tab.
- Most of the packages in NuGet gallery are .NET packages and would not be useful in a C++ project. Microsoft
- recommends adding “native” and “nativepackage” tags to C++ NuGet packages to distinguish them, but even adding
- “native” to search query would still show many .NET-only packages in the list.
-
- Nevertheless, after finding the package you want, click on “Install” button and accept confirmation dialogs.
- After the package is successfully added to the projects, you should be able to build and execute the project
- without the need for making any more changes to build settings.
+ 3. Search for `nlohmann.json`, select it, and click "Install".
- !!! note
+ 
- A few notes:
-
- - NuGet packages are installed per project and not system-wide. The header and binaries for the package are only
- available to the project it is added to, and not other projects (obviously unless we add the package to those
- projects as well)
- - One of the many great things about your elegant work is that it is a header-only library, which makes
- deployment very straightforward. In case of libraries which need binary deployment (`.lib`, `.dll` and `.pdb`
- for debug info) the different binaries for each supported compiler version must be added to the NuGet package.
- Some library creators cram binary versions for all supported Visual C++ compiler versions in the same package,
- so a single package will support all compilers. Some others create a different package for each compiler
- version (and you usually see things like “v140” or “vc141” in package name to clarify which VC++ compiler this
- package supports).
- - Packages can have dependency to other packages, and in this case, NuGet will install all dependencies as well
- as the requested package recursively.
+ 4. `#include ` in your code and build the project. The package's
+ `build/native/nlohmann.json.targets` file adds `$(MSBuildThisFileDirectory)include` to the project's
+ `AdditionalIncludeDirectories`, so no further include path configuration is needed.
- **What happens behind the scenes**
-
- After you add a NuGet package, three changes occur in the project source directory. Of course, we could make these
- changes manually instead of using GUI:
-
- 
-
- 1. A `packages.config` file will be created (or updated to include the package name if one such file already
- exists). This file contains a list of the packages required by this project (name and minimum version) and must
- be added to the project source code repository, so if you move the source code to a new machine, MSBuild/NuGet
- knows which packages it has to restore (which it does automatically before each build).
-
- ```xml
-
-
-
-
- ```
-
- 2. A `packages` folder which contains actual files in the packages (these are header and binary files required for
- a successful build, plus a few metadata files). In case of this library for example, it contains `json.hpp`:
-
- 
-
- !!! note
-
- This directory should not be added to the project source code repository, as it will be restored before each
- build by MSBuild/NuGet. If you go ahead and delete this folder, then build the project again, it will
- magically re-appear!
-
- 3. Project MSBuild makefile (which for Visual C++ projects has a .vcxproj extension) will be updated to include
- settings from the package.
-
- 
-
- The important bit for us here is line 170, which tells MSBuild to import settings from
- `packages\nlohmann.json.3.5.0\build\native\nlohmann.json.targets` file. This is a file the package creator
- created and added to the package (you can see it is one of the two files I created in this repository, the other
- just contains package attributes like name and version number). What does it contain?
-
- For our header-only repository, the only setting we need is to add our include directory to the list of
- `AdditionalIncludeDirectories`:
-
- ```xml
-
-
-
-
- $(MSBuildThisFileDirectory)include;%(AdditionalIncludeDirectories)
-
-
-
- ```
-
- For libraries with binary files, we will need to add `.lib` files to linker inputs and add settings to copy
- `.dll` and other redistributable files to output directory, if needed.
-
- There are other changes to the makefile as well:
-
- - Lines 165-167 add the `packages.config` as one of project files (so it is shown in Solution Explorer tree
- view). It is added as None (no build action) and removing it wouldn’t affect build.
-
- - Lines 172-177 check to ensure the required packages are present. This will display a build error if package
- directory is empty (for example when NuGet cannot restore packages because Internet connection is down).
- Again, if you omit this section, the only change in build would be a more cryptic error message if build
- fails.
-
- !!! note
-
- Changes to .vcxproj makefile should also be added to project source code repository.
-
- As you can see, the mechanism NuGet uses to modify project settings is through MSBuild makefiles, so using NuGet
- with other build systems and compilers (like CMake) as a dependency manager is either impossible or more problematic
- than useful.
-
-Please refer to [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) for
-more information.
+For further details, see the [original discussion](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255)
+this section is based on.
## Conda
@@ -582,7 +547,7 @@ more information.
package: [**`nlohmann_json`**](https://anaconda.org/conda-forge/nlohmann_json)
- - 
+ - [](https://anaconda.org/conda-forge/nlohmann_json)
- :octicons-tag-24: Available versions: current and previous versions
- :octicons-rocket-24: The package is updated with every release.
- :octicons-file-24: File issues at the [feedstock's issue tracker](https://github.com/conda-forge/nlohmann_json-feedstock/issues)
@@ -595,7 +560,7 @@ If you are using [conda](https://conda.io/), you can use the package
conda install -c conda-forge nlohmann_json
```
-??? example
+??? example "Example: Raw compilation"
1. Create the following file:
@@ -624,14 +589,37 @@ conda install -c conda-forge nlohmann_json
## MSYS2
-If you are using [MSYS2](http://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json) package, type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation. Please file issues [here](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D) if you experience problems with the packages.
+!!! abstract "Summary"
-[](https://repology.org/project/nlohmann-json/versions)
-[](https://repology.org/project/nlohmann-json/versions)
-[](https://repology.org/project/nlohmann-json/versions)
-[](https://repology.org/project/nlohmann-json/versions)
+ package: [**`mingw-w64-nlohmann-json`**](https://packages.msys2.org/base/mingw-w64-nlohmann-json)
-:material-update: The [package](https://packages.msys2.org/base/mingw-w64-nlohmann-json) is updated automatically.
+ - [](https://packages.msys2.org/base/mingw-w64-nlohmann-json)
+ - :octicons-rocket-24: The [package](https://packages.msys2.org/base/mingw-w64-nlohmann-json) is updated automatically.
+ - :octicons-file-24: File issues at the [MINGW-packages issue tracker](https://github.com/msys2/MINGW-packages/issues/new?title=%5Bnlohmann-json%5D)
+ - :octicons-question-24: [MSYS2 website](http://www.msys2.org/)
+
+If you are using [MSYS2](http://www.msys2.org/), you can use the [mingw-w64-nlohmann-json](https://packages.msys2.org/base/mingw-w64-nlohmann-json)
+package; type `pacman -S mingw-w64-i686-nlohmann-json` or `pacman -S mingw-w64-x86_64-nlohmann-json` for installation.
+
+??? example "Example: Raw compilation"
+
+ 1. Create the following file:
+
+ ```cpp title="example.cpp"
+ --8<-- "integration/msys2/example.cpp"
+ ```
+
+ 2. Install the package (from an MSYS2 MinGW 64-bit shell):
+
+ ```shell
+ pacman -S mingw-w64-x86_64-nlohmann-json
+ ```
+
+ 3. Compile the code:
+
+ ```shell
+ g++ example.cpp -std=c++11 -o example
+ ```
## MacPorts
@@ -639,7 +627,7 @@ If you are using [MSYS2](http://www.msys2.org/), you can use the [mingw-w64-nloh
port: [**`nlohmann-json`**](https://ports.macports.org/port/nlohmann-json/)
- - [](https://repology.org/project/nlohmann-json/versions)
+ - [](https://ports.macports.org/port/nlohmann-json/)
- :octicons-tag-24: Available versions: current version
- :octicons-rocket-24: The port is updated with every release.
- :octicons-file-24: File issues at the [MacPorts issue tracker](https://trac.macports.org/newticket?port=nlohmann-json)
@@ -841,7 +829,7 @@ If you are using [`CPM.cmake`](https://github.com/TheLartians/CPM.cmake), add th
CPMAddPackage("gh:nlohmann/json@3.12.0")
```
-??? example
+??? example "Example: CMake with `CPMAddPackage`"
1. Create the following files:
@@ -878,7 +866,7 @@ CPMAddPackage("gh:nlohmann/json@3.12.0")
- :octicons-file-24: File issues at the [xmake issue tracker](https://github.com/xmake-io/xmake-repo/issues)
- :octicons-question-24: [xmake website](https://xmake.io/#/)
-??? example
+??? example "Example: xmake project"
1. Create the following files:
@@ -906,18 +894,14 @@ CPMAddPackage("gh:nlohmann/json@3.12.0")
## Other package managers
-The library is also contained in many other package repositories: [](https://repology.org/project/nlohmann-json/versions)
-
-??? example "Package version overview"
-
- [](https://repology.org/project/nlohmann-json/versions)
-
+The library is also contained in many other package repositories; [Repology](https://repology.org/project/nlohmann-json/versions) tracks the packaged
+versions across repositories.
* * *
## Buckaroo
-If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).
+If you are using [Buckaroo](https://github.com/LoopPerfect/buckaroo), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).
!!! warning
@@ -928,7 +912,14 @@ If you are using [Buckaroo](https://buckaroo.pm), you can install this library's
If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'`
to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues
-[here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
+at [the repository](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/), as its issue tracker is no longer
+reachable.
+
+[](https://cocoapods.org/pods/nlohmann_json)
+
+!!! warning
+
+ The module is outdated as the respective [pod](https://cocoapods.org/pods/nlohmann_json) has not been updated in years.
## npm
@@ -944,9 +935,3 @@ There is no official package published to the [ESP-IDF Component Registry](https
new release and can be used as an unofficial component/package for ESP-IDF and PlatformIO projects. As the library
is header-only, it can otherwise be used directly by adding its `include/` directory to your component's/project's
include paths, like any other integration method described on this page.
-
-
-
-!!! warning
-
- The module is outdated as the respective [pod](https://cocoapods.org/pods/nlohmann_json) has not been updated in years.
diff --git a/docs/mkdocs/docs/integration/pkg-config.md b/docs/mkdocs/docs/integration/pkg-config.md
index 429d0dea9..8b2e9047a 100644
--- a/docs/mkdocs/docs/integration/pkg-config.md
+++ b/docs/mkdocs/docs/integration/pkg-config.md
@@ -6,6 +6,9 @@ If you are using bare Makefiles, you can use `pkg-config` to generate the includ
pkg-config nlohmann_json --cflags
```
+A pkg-config file is installed by [CMake](cmake.md#json_install) (when the `JSON_Install` option is enabled, which is
+the default for a top-level build) as well as by several [package managers](package_managers.md).
+
Users of the [Meson build system](package_managers.md#meson) will also be able to use a system-wide library, which will be found by `pkg-config`:
```meson
diff --git a/docs/mkdocs/docs/integration/swift/Package.swift b/docs/mkdocs/docs/integration/swift/Package.swift
new file mode 100644
index 000000000..438ab8ccd
--- /dev/null
+++ b/docs/mkdocs/docs/integration/swift/Package.swift
@@ -0,0 +1,17 @@
+// swift-tools-version: 5.9
+import PackageDescription
+
+let package = Package(
+ name: "json_example",
+ dependencies: [
+ .package(url: "https://github.com/nlohmann/json", from: "3.12.0")
+ ],
+ targets: [
+ .executableTarget(
+ name: "json_example",
+ dependencies: [
+ .product(name: "json", package: "json")
+ ]
+ )
+ ]
+)
diff --git a/docs/mkdocs/docs/integration/swift/example.cpp b/docs/mkdocs/docs/integration/swift/example.cpp
new file mode 100644
index 000000000..ad0a06827
--- /dev/null
+++ b/docs/mkdocs/docs/integration/swift/example.cpp
@@ -0,0 +1,10 @@
+#include
+#include
+#include
+
+using json = nlohmann::json;
+
+int main()
+{
+ std::cout << std::setw(4) << json::meta() << std::endl;
+}
diff --git a/docs/mkdocs/hooks/unreleased_versions.py b/docs/mkdocs/hooks/unreleased_versions.py
new file mode 100644
index 000000000..3f88b73f6
--- /dev/null
+++ b/docs/mkdocs/hooks/unreleased_versions.py
@@ -0,0 +1,82 @@
+"""Mark version numbers newer than the latest release with an "unreleased" badge."""
+
+# The documentation is published from the develop branch and already describes the next release ("Added in version
+# 3.13.0."). Every "version X.Y.Z" newer than the version in include/nlohmann/detail/abi_macros.hpp (which is only
+# bumped when a release is made) gets a badge, so readers of a released version can tell which features they do not
+# have yet; after a release, the badges disappear. Fenced and inline code, headings (a badge would change their
+# anchor), and admonition/tab titles are left untouched, and statements about the future ("will be removed in version
+# 4.0.0") are skipped. copy_markdown_source.py copies the raw source, so the *.md copies are unaffected.
+
+import logging
+import os
+import re
+
+log = logging.getLogger("mkdocs.hooks.unreleased_versions")
+
+_HEADER = os.path.join("..", "..", "include", "nlohmann", "detail", "abi_macros.hpp") # relative to mkdocs.yml
+_VERSION_MACRO = re.compile(r"^#define NLOHMANN_JSON_VERSION_(MAJOR|MINOR|PATCH) (\d+)", re.MULTILINE)
+_MENTION = re.compile(r"\b[Vv]ersion\s+(\d+)\.(\d+)\.(\d+)\b")
+_FUTURE = re.compile(r"\b(?:will|planned|ahead of|until)\b[^.;:!?]*$", re.IGNORECASE)
+_FENCE = re.compile(r"^\s*(`{3,}|~{3,})")
+_NO_BADGE = re.compile(r"^\s*(?:#{1,6}(?:\s|$)|]|(?:!!!|\?\?\?\+?|===)\s)")
+_NEW_BLOCK = re.compile(r"^\s*(?:[-*+]|\d+\.)\s")
+_INLINE_CODE = re.compile(r"(`+).+?\1")
+
+_released = None
+_badge = ""
+
+
+def on_config(config):
+ global _released, _badge
+ path = os.path.join(os.path.dirname(config.config_file_path), _HEADER)
+ try:
+ with open(path, encoding="utf-8") as header:
+ parts = dict(_VERSION_MACRO.findall(header.read()))
+ _released = (int(parts["MAJOR"]), int(parts["MINOR"]), int(parts["PATCH"]))
+ except (OSError, KeyError) as error:
+ _released = None
+ log.info(f"not marking unreleased versions: cannot read {path} ({error})") # info: must not break --strict
+ return
+ version = ".".join(map(str, _released))
+ _badge = (f' unreleased')
+
+
+def on_page_markdown(markdown, *, page, config, files):
+ if _released is None:
+ return markdown
+ lines, fence, context = [], None, ""
+ for line in markdown.split("\n"):
+ original = line
+ match = _FENCE.match(line)
+ if fence:
+ if match and line.strip() == match.group(1) and match.group(1)[0] == fence[0] \
+ and len(match.group(1)) >= len(fence):
+ fence = None
+ elif match:
+ fence = match.group(1)
+ elif not _NO_BADGE.match(line):
+ line = _mark_line(line, "" if _NEW_BLOCK.match(line) else context)
+ lines.append(line)
+ # the previous line catches statements like "will be removed in\nversion 4.0.0"
+ context = original if original.strip() else ""
+ return "\n".join(lines)
+
+
+def _mark_line(line, context):
+ result, position = [], 0
+ for code in _INLINE_CODE.finditer(line):
+ result.append(_mark_text(line[position:code.start()], context + " " + line[:position]))
+ result.append(code.group(0))
+ position = code.end()
+ result.append(_mark_text(line[position:], context + " " + line[:position]))
+ return "".join(result)
+
+
+def _mark_text(text, before):
+ def badge(match):
+ version = tuple(int(part) for part in match.groups())
+ if version <= _released or _FUTURE.search(before + text[:match.start()]):
+ return match.group(0)
+ return match.group(0) + _badge
+ return _MENTION.sub(badge, text)
diff --git a/docs/mkdocs/mkdocs.yml b/docs/mkdocs/mkdocs.yml
index 765f8abbd..46a4aa760 100644
--- a/docs/mkdocs/mkdocs.yml
+++ b/docs/mkdocs/mkdocs.yml
@@ -85,12 +85,14 @@ nav:
- features/modules.md
- 'nlohmann Namespace': features/namespace.md
- features/object_order.md
+ - features/performance.md
- Parsing:
- features/parsing/index.md
- features/parsing/json_lines.md
- features/parsing/parse_exceptions.md
- features/parsing/parser_callbacks.md
- features/parsing/sax_interface.md
+ - features/parsing/untrusted_input.md
- features/assertions.md
- features/serialization.md
- features/enum_conversion.md
@@ -293,6 +295,8 @@ nav:
- '(constructor)': api/byte_container_with_subtype/byte_container_with_subtype.md
- 'clear_subtype': api/byte_container_with_subtype/clear_subtype.md
- 'has_subtype': api/byte_container_with_subtype/has_subtype.md
+ - 'operator==': api/byte_container_with_subtype/operator_eq.md
+ - 'operator!=': api/byte_container_with_subtype/operator_ne.md
- 'set_subtype': api/byte_container_with_subtype/set_subtype.md
- 'subtype': api/byte_container_with_subtype/subtype.md
- adl_serializer:
@@ -310,6 +314,7 @@ nav:
- 'operator string_t': api/json_pointer/operator_string_t.md
- 'operator==': api/json_pointer/operator_eq.md
- 'operator!=': api/json_pointer/operator_ne.md
+ - 'operator<=>': api/json_pointer/operator_spaceship.md
- 'operator/': api/json_pointer/operator_slash.md
- 'operator/=': api/json_pointer/operator_slasheq.md
- 'parent_pointer': api/json_pointer/parent_pointer.md
@@ -352,7 +357,7 @@ nav:
- 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md
- 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.md
- 'JSON_DISABLE_TUPLE_REFERENCE_CONVERSION': api/macros/json_disable_tuple_reference_conversion.md
- - 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md
+ - 'JSON_HAS_CPP_11, JSON_HAS_CPP_14, JSON_HAS_CPP_17, JSON_HAS_CPP_20, JSON_HAS_CPP_23, JSON_HAS_CPP_26': api/macros/json_has_cpp_11.md
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM, JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.md
- 'JSON_HAS_STATIC_RTTI': api/macros/json_has_static_rtti.md
@@ -444,8 +449,21 @@ markdown_extensions:
auto_append:
- ../includes/glossary.md
+# report broken links, anchors, and nav entries as warnings, so that `mkdocs build --strict` (make build) fails
+validation:
+ nav:
+ omitted_files: warn
+ not_found: warn
+ absolute_links: warn
+ links:
+ not_found: warn
+ anchors: warn
+ absolute_links: warn
+ unrecognized_links: warn
+
hooks:
- hooks/copy_markdown_source.py
+ - hooks/unreleased_versions.py
plugins:
- search:
@@ -453,7 +471,8 @@ plugins:
lang: en
- minify:
minify_html: true
- - git-revision-date-localized
+ - git-revision-date-localized:
+ strict: false # log "has no git logs" for uncommitted pages as info, not as a warning
- redirects:
redirect_maps:
'api/basic_json/operator_gtgt.md': api/operator_gtgt.md
@@ -464,9 +483,25 @@ plugins:
'home/code_of_conduct.md': community/code_of_conduct.md
- htmlproofer: # see https://github.com/manuzhang/mkdocs-htmlproofer-plugin
enabled: !ENV [ENABLED_HTMLPROOFER, False]
+ raise_error_after_finish: true # log every broken link, then fail
+ skip_downloads: true # check headers only (customers.md links large PDFs)
+ raise_error_excludes: # integer status codes, fnmatch patterns
+ 403: ['*'] # bot protection against the plugin's "Bot " user agent
+ 429: ['*'] # rate limiting (hundreds of github.com URLs)
+ 502: ['*']
+ 503: ['*']
+ 504: ['*'] # timeouts are reported as 504
+ -1: # connection errors
+ - 'https://repology.org/*' # repology.org is suspended since 2026-09
+ - 'http://2ak5ape.257.cz/' # customers.md: kept although unreachable
+ 401: ['https://fossies.org/*'] # answers the plugin's user agent with 401, browsers and curl with 200
+ 404:
+ - 'https://gitlab.b-data.ch/*' # answers the plugin's user agent with 404, browsers with 200
+ # customers.md: kept although dead
+ - 'https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/CiscoWebexDeskCamera-23-1622100417.pdf'
+ - 'https://docs.cyberark.com/Downloads/Legal/Privileged%20Session%20Manager%20for%20SSH%20Third-Party%20Notices.pdf'
+ 500: ['https://marne.io/licenses'] # customers.md: kept although dead
ignore_urls:
- - http://nlohmann.github.io/json/*
- - https://nlohmann.github.io/json/*
- mailto:*
- privacy:
# repology.org refuses requests from GitHub Actions runners, which made
diff --git a/docs/mkdocs/scripts/check_structure.py b/docs/mkdocs/scripts/check_structure.py
index 78ad0d9fa..dd76dbab0 100755
--- a/docs/mkdocs/scripts/check_structure.py
+++ b/docs/mkdocs/scripts/check_structure.py
@@ -4,6 +4,7 @@ import glob
import os.path
import re
import sys
+import urllib.parse
import yaml
@@ -152,7 +153,7 @@ def check_structure() -> None:
def check_examples() -> None:
- example_files = sorted(glob.glob("../../examples/*.cpp"))
+ example_files = sorted(glob.glob("examples/*.cpp"))
markdown_files = sorted(glob.glob("**/*.md", recursive=True))
# check if every example file is used in at least one markdown file
@@ -211,11 +212,122 @@ def check_links() -> None:
report("nav/duplicate_files", "mkdocs.yml", f'file "{duplicate_file}" is linked with multiple keys in "nav": {file_list_str}; only one is rendered properly, see #4564')
+FENCE_RE = re.compile(r"^\s*(`{3,}|~{3,})")
+INLINE_CODE_RE = re.compile(r"(`+).+?\1")
+
+
+def markdown_lines(file):
+ """Yield (lineno, line) for all lines outside fenced code blocks."""
+ fence = None
+ with open(file, encoding="utf-8") as content:
+ for lineno, line in enumerate(content, 1):
+ line = line.rstrip("\n")
+ match = FENCE_RE.match(line)
+ if fence is None:
+ if match:
+ fence = match.group(1)
+ else:
+ yield lineno, line
+ elif match and line.strip() == match.group(1) and match.group(1)[0] == fence[0] \
+ and len(match.group(1)) >= len(fence):
+ fence = None
+
+
+def check_example_titles() -> None:
+ """On API pages with more than one example, every example needs a title of the form "Example: ..."."""
+ example_re = re.compile(r'^\s*(?:\?\?\?\+?|!!!) example(?: "(.*)")?\s*$')
+ for file in sorted(glob.glob("api/**/*.md", recursive=True)):
+ examples = [(lineno, m.group(1)) for lineno, line in markdown_lines(file) if (m := example_re.match(line))]
+ if len(examples) < 2:
+ continue
+ for lineno, title in examples:
+ if title is None or not title.startswith("Example: "):
+ report("style/example_title", f"{file}:{lineno}",
+ f'pages with several examples need titles like "Example: ..." (found: {title!r})')
+
+
+def check_heading_levels() -> None:
+ """Headings start at level 1 and never skip a level."""
+ heading_re = re.compile(r"^(#{1,6})\s|^]")
+ for file in sorted(glob.glob("**/*.md", recursive=True)):
+ previous = 0
+ for lineno, line in markdown_lines(file):
+ match = heading_re.match(line)
+ if not match:
+ continue
+ level = len(match.group(1)) if match.group(1) else int(match.group(2))
+ if previous == 0 and level != 1:
+ report("structure/heading_level", f"{file}:{lineno}", f"first heading should have level 1, not {level}")
+ elif level > previous + 1 and previous != 0:
+ report("structure/heading_level", f"{file}:{lineno}", f"heading level jumps from {previous} to {level}")
+ previous = level
+
+
+def check_image_alt_text() -> None:
+ """Images need an alternative text."""
+ empty_alt_re = re.compile(r"!\[\s*\][(\[]")
+ img_re = re.compile(r"
]*>", re.IGNORECASE)
+ alt_re = re.compile(r'\balt\s*=\s*"[^"]*\S[^"]*"', re.IGNORECASE)
+ for file in sorted(glob.glob("**/*.md", recursive=True)):
+ for lineno, line in markdown_lines(file):
+ line = INLINE_CODE_RE.sub("", line)
+ if empty_alt_re.search(line) or any(not alt_re.search(tag) for tag in img_re.findall(line)):
+ report("style/image_alt_text", f"{file}:{lineno}", "image without alternative text")
+
+
+def check_header_links() -> None:
+ """Links to the documentation in the library's headers point to existing pages."""
+ url_re = re.compile(r"https://json\.nlohmann\.me/([^\s#)>\"']*)")
+ for header in sorted(glob.glob("../../../include/nlohmann/**/*.hpp", recursive=True)):
+ with open(header, encoding="utf-8") as content:
+ for lineno, line in enumerate(content, 1):
+ for match in url_re.finditer(line):
+ path = urllib.parse.unquote(match.group(1)).strip("/")
+ if path and not (os.path.isfile(f"{path}.md") or os.path.isfile(f"{path}/index.md")):
+ report("links/header_link", f"{os.path.relpath(header, '../../..')}:{lineno}",
+ f'link to "{match.group(0)}" does not point to a documentation page')
+
+
+def check_docset() -> None:
+ """Every API page and every macro has an entry in the docset index; no entry points to a missing page."""
+ entry_re = re.compile(r"VALUES \('((?:[^']|'')*)', '(\w+)', '([^']*)'\);")
+ names_by_path = {}
+ with open("../../docset/docSet.sql", encoding="utf-8") as sql:
+ for name, _, path in entry_re.findall(sql.read()):
+ names_by_path.setdefault(path, set()).add(name.replace("''", "'"))
+
+ def to_path(page):
+ if os.path.basename(page) == "index.md":
+ return page[:-len("index.md")] + "index.html"
+ return page[:-len(".md")] + "/index.html"
+
+ pages = sorted(glob.glob("**/*.md", recursive=True))
+ for path in sorted(set(names_by_path) - {to_path(p) for p in pages}):
+ report("docset/stale_entry", "../../docset/docSet.sql", f'entry "{path}" has no documentation page')
+ for page in (p for p in pages if p.startswith("api/")):
+ names = names_by_path.get(to_path(page))
+ if not names:
+ report("docset/missing_entry", page, "page has no entry in docs/docset/docSet.sql")
+ elif page.startswith("api/macros/") and os.path.basename(page) != "index.md":
+ with open(page, encoding="utf-8") as content:
+ text = content.read()
+ match = re.search(r"^# (.+)$", text, re.MULTILINE) or re.search(r"(.*?)
", text, re.DOTALL)
+ title = re.sub(r"<[^>]+>|\s+", " ", match.group(1))
+ for macro in filter(None, (x.strip() for x in re.split(r"[,/]", title))):
+ if macro not in names:
+ report("docset/missing_macro", page, f'macro "{macro}" has no entry in docs/docset/docSet.sql')
+
+
if __name__ == "__main__":
print(120 * "-")
check_structure()
check_examples()
check_links()
+ check_example_titles()
+ check_heading_levels()
+ check_image_alt_text()
+ check_header_links()
+ check_docset()
print(120 * "-")
if warnings > 0:
diff --git a/docs/mkdocs/scripts/check_version_history.py b/docs/mkdocs/scripts/check_version_history.py
new file mode 100644
index 000000000..81d629500
--- /dev/null
+++ b/docs/mkdocs/scripts/check_version_history.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+"""Check the "Added in version" entries of the macro pages against the git tags.
+
+For every macro documented in docs/api/macros, find the first release tag whose amalgamated header mentions the macro
+and compare it with the version the page's "Version history" names. A macro documented as added *before* it appears
+in any release, or documented with a released version although no release contains it, is reported as a problem. A
+macro that appears in the header *before* its documented version is only a note: many macros existed internally before
+they were documented for users. The check is heuristic and meant to be run by hand, not in CI.
+
+usage: python3 check_version_history.py (from docs/mkdocs/docs, needs the git tags)
+"""
+
+import functools
+import glob
+import re
+# the script only runs git with fixed arguments and without a shell
+import subprocess # nosec B404
+import sys
+
+HEADER_PATHS = ["single_include/nlohmann/json.hpp", "src/json.hpp"] # older releases used src/json.hpp
+VERSION_RE = re.compile(r"[Aa]dded in (?:version )?(\d+)\.(\d+)\.(\d+)")
+NAMED_VERSION_RE = re.compile(r"[Aa]dded `([A-Z0-9_]+)` in (?:version )?(\d+)\.(\d+)\.(\d+)")
+
+
+def release_tags():
+ # fixed git command without a shell
+ tags = subprocess.run(["git", "tag", "-l", "v*"], capture_output=True, text=True, check=True).stdout.split() # nosec B603, B607
+ versions = []
+ for tag in tags:
+ match = re.fullmatch(r"v(\d+)\.(\d+)\.(\d+)", tag)
+ if match:
+ versions.append((tuple(map(int, match.groups())), tag))
+ return sorted(versions)
+
+
+@functools.lru_cache(maxsize=None)
+def header(tag):
+ for path in HEADER_PATHS:
+ # fixed git command without a shell; the tag names come from "git tag"
+ result = subprocess.run(["git", "show", f"{tag}:{path}"], capture_output=True, text=True) # nosec B603, B607
+ if result.returncode == 0:
+ return result.stdout
+ return ""
+
+
+def macros_and_versions(page):
+ with open(page, encoding="utf-8") as content:
+ text = content.read()
+ match = re.search(r"^# (.+)$", text, re.MULTILINE) or re.search(r"(.*?)
", text, re.DOTALL)
+ title = re.sub(r"<[^>]+>|\s+", " ", match.group(1))
+ macros = [x.strip() for x in re.split(r"[,/]", title) if x.strip()]
+ history = text.split("## Version history", 1)[-1]
+ entries = re.split(r"\n(?=\s*(?:\d+\.|-)\s)", history)
+ specific = {} # entries like "Added `JSON_HAS_CPP_23` in version 3.12.0."
+ general = []
+ for entry in entries:
+ named = NAMED_VERSION_RE.search(entry)
+ if named:
+ specific[named.group(1)] = tuple(map(int, named.groups()[1:]))
+ continue
+ match = VERSION_RE.search(entry)
+ if match:
+ general.append(tuple(map(int, match.groups())))
+ rest = [macro for macro in macros if macro not in specific]
+ if len(general) == len(rest): # numbered history: one entry per macro, in title order
+ pairs = list(zip(rest, general))
+ else:
+ pairs = [(macro, general[0]) for macro in rest] if general else []
+ return pairs + sorted(specific.items())
+
+
+def main():
+ tags = release_tags()
+ latest = tags[-1][0]
+ problems = notes = 0
+ for page in sorted(glob.glob("api/macros/*.md")):
+ if page.endswith("index.md"):
+ continue
+ for macro, documented in macros_and_versions(page):
+ pattern = re.compile(rf"\b{re.escape(macro)}\b")
+ first = next((version for version, tag in tags if pattern.search(header(tag))), None)
+ fmt = ".".join
+ if first is None:
+ if documented <= latest:
+ problems += 1
+ print(f"{page}: {macro} is documented as added in {fmt(map(str, documented))}, "
+ f"but no release up to {fmt(map(str, latest))} contains it")
+ elif documented < first:
+ problems += 1
+ print(f"{page}: {macro} is documented as added in {fmt(map(str, documented))}, "
+ f"but first appears in {fmt(map(str, first))}")
+ elif documented > first:
+ notes += 1
+ print(f"{page}: note: {macro} is documented as added in {fmt(map(str, documented))}, "
+ f"but is mentioned in the header since {fmt(map(str, first))}")
+ print(f"{problems} possible problem(s), {notes} note(s)")
+ return 1 if problems else 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/docs/mkdocs/scripts/mermaid/check_mermaid.mjs b/docs/mkdocs/scripts/mermaid/check_mermaid.mjs
new file mode 100644
index 000000000..bb0f20722
--- /dev/null
+++ b/docs/mkdocs/scripts/mermaid/check_mermaid.mjs
@@ -0,0 +1,54 @@
+// Check that every Mermaid diagram in the documentation parses.
+//
+// MkDocs does not validate Mermaid diagrams; a syntax error only shows up as an error box in the browser. This script
+// extracts every ```mermaid block from the Markdown files and runs it through mermaid.parse(), the same parser the
+// site uses (Material for MkDocs loads mermaid@11). Mermaid needs a DOM (DOMPurify), so jsdom provides one; the globals
+// must be set before Mermaid is imported, hence the dynamic import.
+//
+// usage: node check_mermaid.mjs
+
+import { readdirSync, readFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { JSDOM } from 'jsdom';
+
+const { window } = new JSDOM('', { pretendToBeVisual: true });
+globalThis.window = window;
+globalThis.document = window.document;
+globalThis.DOMParser = window.DOMParser;
+const { default: mermaid } = await import('mermaid');
+mermaid.initialize({ startOnLoad: false });
+
+const docsDir = process.argv[2] ?? 'docs';
+const opening = /^(\s*)(`{3,}|~{3,})\s*mermaid\s*$/;
+let diagrams = 0;
+let errors = 0;
+
+for (const file of readdirSync(docsDir, { recursive: true }).filter((f) => f.endsWith('.md')).sort()) {
+ const lines = readFileSync(join(docsDir, file), 'utf8').split('\n');
+ for (let i = 0; i < lines.length; ++i) {
+ const match = opening.exec(lines[i]);
+ if (!match) {
+ continue;
+ }
+ // strip the indentation of the opening fence from every line (blocks inside admonitions or lists), like
+ // pymdownx.superfences does
+ const [, indent, fence] = match;
+ const closing = new RegExp(`^\\s*\\${fence[0]}{${fence.length},}\\s*$`);
+ const body = [];
+ let j = i + 1;
+ for (; j < lines.length && !closing.test(lines[j]); ++j) {
+ body.push(lines[j].startsWith(indent) ? lines[j].slice(indent.length) : lines[j].trimStart());
+ }
+ ++diagrams;
+ try {
+ await mermaid.parse(body.join('\n'));
+ } catch (error) {
+ ++errors;
+ console.log(`${join(docsDir, file)}:${i + 1}: ${String(error?.message ?? error).replaceAll('\n', '\n ')}`);
+ }
+ i = j;
+ }
+}
+
+console.log(`checked ${diagrams} Mermaid diagrams, ${errors} invalid`);
+process.exitCode = errors ? 1 : 0;
diff --git a/docs/mkdocs/scripts/mermaid/package-lock.json b/docs/mkdocs/scripts/mermaid/package-lock.json
new file mode 100644
index 000000000..7fbbf6226
--- /dev/null
+++ b/docs/mkdocs/scripts/mermaid/package-lock.json
@@ -0,0 +1,1619 @@
+{
+ "name": "check-mermaid",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "check-mermaid",
+ "dependencies": {
+ "jsdom": "30.1.1",
+ "mermaid": "11.17.2"
+ }
+ },
+ "node_modules/@antfu/install-pkg": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-2.1.0.tgz",
+ "integrity": "sha512-sdg9NxU3zR4Mnawfbc/x6GB5Wf17WYud5qOuEuxXjaKpYpMkISSJEjItGebXJ2bQ4DIcly4NYH23mtkGJjvKUw==",
+ "license": "MIT",
+ "dependencies": {
+ "package-manager-detector": "^1.8.0",
+ "tinyexec": "^1.3.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/@asamuzakjp/css-color": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-7.1.2.tgz",
+ "integrity": "sha512-99DHAnXDB5z6EEK+9GMpVI7Mw4oxj97dY5bpOzMnjADQWxI8rN6TvTduuFLUhUMlS7/CfVZ06tcZsus6cltnNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/css-calc": "^3.4.1",
+ "@csstools/css-color-parser": "^4.2.4",
+ "@csstools/css-parser-algorithms": "^4.0.1",
+ "@csstools/css-tokenizer": "^4.0.2",
+ "lru-cache": "^11.5.3"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@asamuzakjp/dom-selector": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-9.2.2.tgz",
+ "integrity": "sha512-lSWTBMjAcmu2xn5yEDU7jh6QDV+C8GEKtdJ4pIQhXh26RkKQ7S3FuQlt+zZkUbTdJ4d3XyV1kPI/G0zWXxqaqw==",
+ "license": "MIT",
+ "dependencies": {
+ "bidi-js": "^1.1.0",
+ "css-tree": "^3.2.1",
+ "is-potential-custom-element-name": "^1.0.1",
+ "lru-cache": "^11.5.3"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@braintree/sanitize-url": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz",
+ "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==",
+ "license": "MIT"
+ },
+ "node_modules/@bramus/specificity": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz",
+ "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==",
+ "license": "MIT",
+ "dependencies": {
+ "css-tree": "^3.0.0"
+ },
+ "bin": {
+ "specificity": "bin/cli.js"
+ }
+ },
+ "node_modules/@chevrotain/types": {
+ "version": "11.1.2",
+ "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz",
+ "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@csstools/color-helpers": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.2.tgz",
+ "integrity": "sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "engines": {
+ "node": ">=20.19.0"
+ }
+ },
+ "node_modules/@csstools/css-calc": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.1.tgz",
+ "integrity": "sha512-EtC7SoN1j6J4E4DCwg5QgbO5TGxgxIA1RXqe+W+qUM+BUcezx9wT+/tiQ/WO2yCX4i5X+Cuf9ciJ22aP4UEwWw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^4.0.1",
+ "@csstools/css-tokenizer": "^4.0.2"
+ }
+ },
+ "node_modules/@csstools/css-color-parser": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.4.tgz",
+ "integrity": "sha512-DyefytAZ735mX4Dq/WcDAXFtXhaEFvme0ZS9tVEBAc2whxUthXr0R0L2rmEPm59SrMBkGrFzQviBXMs/UtnABQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "@csstools/color-helpers": "^6.1.2",
+ "@csstools/css-calc": "^3.4.1"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^4.0.1",
+ "@csstools/css-tokenizer": "^4.0.2"
+ }
+ },
+ "node_modules/@csstools/css-parser-algorithms": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.1.tgz",
+ "integrity": "sha512-ShL8BqPfbKJrJiKFH0xBbN0i7Nrh9HXYRuF+pzyj93R/BL2YAsUxJeqANErzqM+0JGl7vjHp+3OIgd/DL69YIA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "peerDependencies": {
+ "@csstools/css-tokenizer": "^4.0.2"
+ }
+ },
+ "node_modules/@csstools/css-syntax-patches-for-csstree": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.14.tgz",
+ "integrity": "sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT-0",
+ "peerDependencies": {
+ "css-tree": "^3.2.1"
+ },
+ "peerDependenciesMeta": {
+ "css-tree": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@csstools/css-tokenizer": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.2.tgz",
+ "integrity": "sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19.0"
+ }
+ },
+ "node_modules/@exodus/bytes": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.16.0.tgz",
+ "integrity": "sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ },
+ "peerDependencies": {
+ "@noble/hashes": "^1.8.0 || ^2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@noble/hashes": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@iconify/types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
+ "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
+ "license": "MIT"
+ },
+ "node_modules/@iconify/utils": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.7.tgz",
+ "integrity": "sha512-JZHlwdID+dy+lTgbYC8NEC4zeugqeYsc6jewvzb4c58kHauJn+X7rNwQjxz5p2qSjqaEeQoLkCIQ9v/H4PK0/w==",
+ "license": "MIT",
+ "dependencies": {
+ "@antfu/install-pkg": "^2.0.1",
+ "@iconify/types": "^2.0.0",
+ "import-meta-resolve": "^4.2.0"
+ }
+ },
+ "node_modules/@mermaid-js/parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.2.1.tgz",
+ "integrity": "sha512-n12NohV3mrUyUL2o93IgG/ifeW9FTyeJn3zDxkhwa8MJ9Fxg3HQMlA3RiGmD/3UnJvheztkjjQAjA2T4LmUcpw==",
+ "license": "MIT",
+ "dependencies": {
+ "@chevrotain/types": "~11.1.2"
+ }
+ },
+ "node_modules/@types/d3": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
+ "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-array": "*",
+ "@types/d3-axis": "*",
+ "@types/d3-brush": "*",
+ "@types/d3-chord": "*",
+ "@types/d3-color": "*",
+ "@types/d3-contour": "*",
+ "@types/d3-delaunay": "*",
+ "@types/d3-dispatch": "*",
+ "@types/d3-drag": "*",
+ "@types/d3-dsv": "*",
+ "@types/d3-ease": "*",
+ "@types/d3-fetch": "*",
+ "@types/d3-force": "*",
+ "@types/d3-format": "*",
+ "@types/d3-geo": "*",
+ "@types/d3-hierarchy": "*",
+ "@types/d3-interpolate": "*",
+ "@types/d3-path": "*",
+ "@types/d3-polygon": "*",
+ "@types/d3-quadtree": "*",
+ "@types/d3-random": "*",
+ "@types/d3-scale": "*",
+ "@types/d3-scale-chromatic": "*",
+ "@types/d3-selection": "*",
+ "@types/d3-shape": "*",
+ "@types/d3-time": "*",
+ "@types/d3-time-format": "*",
+ "@types/d3-timer": "*",
+ "@types/d3-transition": "*",
+ "@types/d3-zoom": "*"
+ }
+ },
+ "node_modules/@types/d3-array": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-axis": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz",
+ "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-brush": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz",
+ "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-chord": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz",
+ "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-contour": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz",
+ "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-array": "*",
+ "@types/geojson": "*"
+ }
+ },
+ "node_modules/@types/d3-delaunay": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-dispatch": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz",
+ "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-drag": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz",
+ "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-dsv": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz",
+ "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-fetch": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz",
+ "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-dsv": "*"
+ }
+ },
+ "node_modules/@types/d3-force": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz",
+ "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-format": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz",
+ "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-geo": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.1.tgz",
+ "integrity": "sha512-65Emv9fQiQQqphLlRkuQ5ypPsOmWPhtBGCMv61JDPEPMvsx+gzhGf74yw1a78xFKPj6zw4AgQICJoQv0vK9M2w==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/geojson": "*"
+ }
+ },
+ "node_modules/@types/d3-hierarchy": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz",
+ "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-polygon": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz",
+ "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-quadtree": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz",
+ "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-random": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz",
+ "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-scale-chromatic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+ "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-selection": {
+ "version": "3.0.12",
+ "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.12.tgz",
+ "integrity": "sha512-Qe/KWYhEiIIxGs7HrAAjMfShxKldx19SJtr5zu53f3afPsdZNz7HHtdTLXo/kqeiWNXVycI24kSnfzBYkTzpgw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-time-format": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz",
+ "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+ "license": "MIT"
+ },
+ "node_modules/@types/d3-transition": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz",
+ "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/d3-zoom": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.9.tgz",
+ "integrity": "sha512-0sE1406XBYJGiqD3AusTl9ZqC//2mIXix51tbom25gDCA8ri4xnSZg28CaSE8Srl6FClqABUKfsn0qghgdepMA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/d3-interpolate": "*",
+ "@types/d3-selection": "*"
+ }
+ },
+ "node_modules/@types/geojson": {
+ "version": "7946.0.16",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@upsetjs/venn.js": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz",
+ "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "d3-selection": "^3.0.0",
+ "d3-transition": "^3.0.1"
+ }
+ },
+ "node_modules/bidi-js": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz",
+ "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==",
+ "license": "MIT",
+ "dependencies": {
+ "require-from-string": "^2.0.2"
+ }
+ },
+ "node_modules/commander": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+ "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/cose-base": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz",
+ "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==",
+ "license": "MIT",
+ "dependencies": {
+ "layout-base": "^1.0.0"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
+ "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.27.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "node_modules/cytoscape": {
+ "version": "3.34.3",
+ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.3.tgz",
+ "integrity": "sha512-yfYGhRcGAntq6YBD583j4n0Eg3jIxvWmZtz/5uz9UYkeIStSlMxuUja+ec5j3iBD8nv1rwaOAYMW09tBdkSeaQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/cytoscape-cose-bilkent": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz",
+ "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cose-base": "^1.0.0"
+ },
+ "peerDependencies": {
+ "cytoscape": "^3.2.0"
+ }
+ },
+ "node_modules/cytoscape-fcose": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz",
+ "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==",
+ "license": "MIT",
+ "dependencies": {
+ "cose-base": "^2.2.0"
+ },
+ "peerDependencies": {
+ "cytoscape": "^3.2.0"
+ }
+ },
+ "node_modules/cytoscape-fcose/node_modules/cose-base": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz",
+ "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==",
+ "license": "MIT",
+ "dependencies": {
+ "layout-base": "^2.0.0"
+ }
+ },
+ "node_modules/cytoscape-fcose/node_modules/layout-base": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz",
+ "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==",
+ "license": "MIT"
+ },
+ "node_modules/d3": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
+ "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "3",
+ "d3-axis": "3",
+ "d3-brush": "3",
+ "d3-chord": "3",
+ "d3-color": "3",
+ "d3-contour": "4",
+ "d3-delaunay": "6",
+ "d3-dispatch": "3",
+ "d3-drag": "3",
+ "d3-dsv": "3",
+ "d3-ease": "3",
+ "d3-fetch": "3",
+ "d3-force": "3",
+ "d3-format": "3",
+ "d3-geo": "3",
+ "d3-hierarchy": "3",
+ "d3-interpolate": "3",
+ "d3-path": "3",
+ "d3-polygon": "3",
+ "d3-quadtree": "3",
+ "d3-random": "3",
+ "d3-scale": "4",
+ "d3-scale-chromatic": "3",
+ "d3-selection": "3",
+ "d3-shape": "3",
+ "d3-time": "3",
+ "d3-time-format": "4",
+ "d3-timer": "3",
+ "d3-transition": "3",
+ "d3-zoom": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "license": "ISC",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-axis": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
+ "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-brush": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
+ "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-drag": "2 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-selection": "3",
+ "d3-transition": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-chord": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
+ "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-contour": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
+ "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-delaunay": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
+ "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
+ "license": "ISC",
+ "dependencies": {
+ "delaunator": "5"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dispatch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-drag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
+ "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-selection": "3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-dsv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
+ "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
+ "license": "ISC",
+ "dependencies": {
+ "commander": "7",
+ "iconv-lite": "0.6",
+ "rw": "1"
+ },
+ "bin": {
+ "csv2json": "bin/dsv2json.js",
+ "csv2tsv": "bin/dsv2dsv.js",
+ "dsv2dsv": "bin/dsv2dsv.js",
+ "dsv2json": "bin/dsv2json.js",
+ "json2csv": "bin/json2dsv.js",
+ "json2dsv": "bin/json2dsv.js",
+ "json2tsv": "bin/json2dsv.js",
+ "tsv2csv": "bin/dsv2dsv.js",
+ "tsv2json": "bin/dsv2json.js"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-fetch": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
+ "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dsv": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-force": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-quadtree": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz",
+ "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-geo": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
+ "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.5.0 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-hierarchy": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
+ "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-polygon": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
+ "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-quadtree": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-random": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
+ "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-sankey": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz",
+ "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "d3-array": "1 - 2",
+ "d3-shape": "^1.2.0"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/d3-array": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
+ "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "internmap": "^1.0.0"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/d3-path": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+ "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/d3-sankey/node_modules/d3-shape": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
+ "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "d3-path": "1"
+ }
+ },
+ "node_modules/d3-sankey/node_modules/internmap": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
+ "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==",
+ "license": "ISC"
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale-chromatic": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
+ "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3",
+ "d3-interpolate": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-selection": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
+ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-transition": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
+ "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-color": "1 - 3",
+ "d3-dispatch": "1 - 3",
+ "d3-ease": "1 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-timer": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "d3-selection": "2 - 3"
+ }
+ },
+ "node_modules/d3-zoom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
+ "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
+ "license": "ISC",
+ "dependencies": {
+ "d3-dispatch": "1 - 3",
+ "d3-drag": "2 - 3",
+ "d3-interpolate": "1 - 3",
+ "d3-selection": "2 - 3",
+ "d3-transition": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/dagre-d3-es": {
+ "version": "7.0.14",
+ "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz",
+ "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==",
+ "license": "MIT",
+ "dependencies": {
+ "d3": "^7.9.0",
+ "lodash-es": "^4.17.21"
+ }
+ },
+ "node_modules/data-urls": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz",
+ "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-mimetype": "^5.0.0",
+ "whatwg-url": "^16.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/data-urls/node_modules/whatwg-url": {
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz",
+ "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==",
+ "license": "MIT",
+ "dependencies": {
+ "@exodus/bytes": "^1.11.0",
+ "tr46": "^6.0.0",
+ "webidl-conversions": "^8.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=24.0.0"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.23",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz",
+ "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==",
+ "license": "MIT"
+ },
+ "node_modules/decimal.js": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz",
+ "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
+ "license": "MIT"
+ },
+ "node_modules/delaunator": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz",
+ "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==",
+ "license": "ISC",
+ "dependencies": {
+ "robust-predicates": "^3.0.2"
+ }
+ },
+ "node_modules/dompurify": {
+ "version": "3.4.16",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.16.tgz",
+ "integrity": "sha512-sqo+pNp3qRhCIpbgRi1y8Tgk27Bo2Ry7w0dC1NBeNTdZChWjz9Xb/KOoZbRP/R6pQZ80Qw8YhXw13hWWBbMRnQ==",
+ "license": "(MPL-2.0 OR Apache-2.0)",
+ "optionalDependencies": {
+ "@types/trusted-types": "^2.0.7"
+ }
+ },
+ "node_modules/entities": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz",
+ "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/es-toolkit": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz",
+ "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==",
+ "license": "MIT",
+ "workspaces": [
+ "docs",
+ "benchmarks",
+ "tests/types",
+ "tests/browser-compat"
+ ]
+ },
+ "node_modules/fastdom": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.12.tgz",
+ "integrity": "sha512-LB+xjSTEbjHE1cWsxu+tN2Xqr1kpi+V9aADI7sVM5ZMaXyYGPHULQMzpJMYqOTULK/73pUkWVzzObFRBkPr+hg==",
+ "license": "MIT",
+ "dependencies": {
+ "strictdom": "^1.0.1"
+ }
+ },
+ "node_modules/hachure-fill": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz",
+ "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==",
+ "license": "MIT"
+ },
+ "node_modules/html-encoding-sniffer": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-7.0.0.tgz",
+ "integrity": "sha512-UikN5yr7xsCDAq87Or5or0PAlD3HJJOKVzM05az588WnpDJ4Ux7a2A53Qi6gofGg2/EtvF/H4hCi/TXfCW4Y6w==",
+ "license": "MIT",
+ "dependencies": {
+ "@exodus/bytes": "^1.15.1"
+ },
+ "engines": {
+ "node": "^22.13.0 || >=24.0.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/import-meta-resolve": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz",
+ "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
+ "license": "MIT"
+ },
+ "node_modules/jsdom": {
+ "version": "30.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.1.1.tgz",
+ "integrity": "sha512-FahmoPK5vbPc+jxV1iErMHmAZypCZ942NHF4+qqaWAuvaKKTBZxawnmAtrbGWLU7MtlxfqIP0qw6aSI+aWGtLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@asamuzakjp/css-color": "^7.0.0",
+ "@asamuzakjp/dom-selector": "^9.2.1",
+ "@bramus/specificity": "^2.4.2",
+ "@csstools/css-syntax-patches-for-csstree": "^1.1.13",
+ "@exodus/bytes": "^1.15.1",
+ "css-tree": "^3.2.1",
+ "data-urls": "^7.0.0",
+ "decimal.js": "^10.6.0",
+ "html-encoding-sniffer": "^7.0.0",
+ "is-potential-custom-element-name": "^1.0.1",
+ "lru-cache": "^11.5.2",
+ "parse5": "^8.0.1",
+ "saxes": "^6.0.0",
+ "tough-cookie": "^6.0.2",
+ "undici": "^8.10.2",
+ "w3c-xmlserializer": "^6.0.0",
+ "webidl-conversions": "^8.0.1",
+ "whatwg-mimetype": "^5.0.0",
+ "whatwg-url": "^17.1.1",
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ },
+ "peerDependencies": {
+ "canvas": "^3.2.3"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/katex": {
+ "version": "0.16.47",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz",
+ "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==",
+ "funding": [
+ "https://opencollective.com/katex",
+ "https://github.com/sponsors/katex"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^8.3.0"
+ },
+ "bin": {
+ "katex": "cli.js"
+ }
+ },
+ "node_modules/katex/node_modules/commander": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/khroma": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz",
+ "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="
+ },
+ "node_modules/layout-base": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz",
+ "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash-es": {
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz",
+ "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==",
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "11.5.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz",
+ "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==",
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/marked": {
+ "version": "16.4.2",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz",
+ "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==",
+ "license": "MIT",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.27.1",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
+ "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
+ "license": "CC0-1.0"
+ },
+ "node_modules/mermaid": {
+ "version": "11.17.2",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.17.2.tgz",
+ "integrity": "sha512-V6K3C8EBdEsPFZXSKMJe6ppQOENxuHARr9GvHX4hh47lAbhMRD9qf4oEK7LoaRQxULMa80/qt5gHO73aCleBBg==",
+ "license": "MIT",
+ "dependencies": {
+ "@braintree/sanitize-url": "^7.1.2",
+ "@iconify/utils": "^3.0.2",
+ "@mermaid-js/parser": "^1.2.1",
+ "@types/d3": "^7.4.3",
+ "@upsetjs/venn.js": "^2.0.0",
+ "cytoscape": "^3.34.0",
+ "cytoscape-cose-bilkent": "^4.1.0",
+ "cytoscape-fcose": "^2.2.0",
+ "d3": "^7.9.0",
+ "d3-sankey": "^0.12.3",
+ "dagre-d3-es": "7.0.14",
+ "dayjs": "^1.11.21",
+ "dompurify": "^3.3.3",
+ "es-toolkit": "^1.45.1",
+ "fastdom": "1.0.12",
+ "katex": "^0.16.47",
+ "khroma": "^2.1.0",
+ "marked": "^16.3.0",
+ "roughjs": "^4.6.6",
+ "stylis": "^4.3.6",
+ "ts-dedent": "^2.2.0",
+ "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0"
+ }
+ },
+ "node_modules/package-manager-detector": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.8.0.tgz",
+ "integrity": "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==",
+ "license": "MIT"
+ },
+ "node_modules/parse5": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
+ "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==",
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^8.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/path-data-parser": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz",
+ "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==",
+ "license": "MIT"
+ },
+ "node_modules/points-on-curve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz",
+ "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==",
+ "license": "MIT"
+ },
+ "node_modules/points-on-path": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz",
+ "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==",
+ "license": "MIT",
+ "dependencies": {
+ "path-data-parser": "0.1.0",
+ "points-on-curve": "0.2.0"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/robust-predicates": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz",
+ "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==",
+ "license": "Unlicense"
+ },
+ "node_modules/roughjs": {
+ "version": "4.6.6",
+ "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz",
+ "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==",
+ "license": "MIT",
+ "dependencies": {
+ "hachure-fill": "^0.5.2",
+ "path-data-parser": "^0.1.0",
+ "points-on-curve": "^0.2.0",
+ "points-on-path": "^0.2.1"
+ }
+ },
+ "node_modules/rw": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "license": "ISC",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strictdom": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/strictdom/-/strictdom-1.0.1.tgz",
+ "integrity": "sha512-cEmp9QeXXRmjj/rVp9oyiqcvyocWab/HaoN4+bwFeZ7QzykJD6L3yD4v12K1x0tHpqRqVpJevN3gW7kyM39Bqg==",
+ "license": "MIT"
+ },
+ "node_modules/stylis": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz",
+ "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==",
+ "license": "MIT"
+ },
+ "node_modules/tinyexec": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz",
+ "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tldts": {
+ "version": "7.4.16",
+ "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.16.tgz",
+ "integrity": "sha512-QwBER5KMR86IIjpIiO7H/Z3IMJPsZ1A6RKPAqzTTgOyUQUSt9FdnKcqhTaJmkY6HVrgouZHZR0ncK5QxvmnQeg==",
+ "license": "MIT",
+ "dependencies": {
+ "tldts-core": "^7.4.16"
+ },
+ "bin": {
+ "tldts": "bin/cli.js"
+ }
+ },
+ "node_modules/tldts-core": {
+ "version": "7.4.16",
+ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.16.tgz",
+ "integrity": "sha512-MDolfaSJtlSK5Y0A1xl3277ekubZwobpBjugknDizI9O5Rm60a1m8k4ICK+MRsCDzPygT81mp3BBf5RKDlFRfA==",
+ "license": "MIT"
+ },
+ "node_modules/tough-cookie": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz",
+ "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tldts": "^7.0.5"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz",
+ "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==",
+ "license": "MIT",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/ts-dedent": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz",
+ "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.10"
+ }
+ },
+ "node_modules/undici": {
+ "version": "8.11.2",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz",
+ "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=22.19.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "14.0.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz",
+ "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist-node/bin/uuid"
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-6.0.0.tgz",
+ "integrity": "sha512-4Nsy8K5Tr6SPDH9jhKJOHf7ChDrc1zufZTVSF7x72hwuEXBqxqk9G6cK+K2NRUtB3iELRJqjXb4JPDMBjMTl2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz",
+ "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz",
+ "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "17.1.2",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.2.tgz",
+ "integrity": "sha512-TEZA+Zqxin7Jjsm2cjRohCmen5awh+hT6Zi3VZdqZlNRk7zvOI/9WpBFg/DWlA56bWnzwm6DuB8NS0EsxQH9uQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@exodus/bytes": "^1.15.1",
+ "tr46": "^6.0.0",
+ "webidl-conversions": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.14.0 || >=24.0.0"
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/docs/mkdocs/scripts/mermaid/package.json b/docs/mkdocs/scripts/mermaid/package.json
new file mode 100644
index 000000000..6cf40b9f6
--- /dev/null
+++ b/docs/mkdocs/scripts/mermaid/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "check-mermaid",
+ "private": true,
+ "description": "Validate the Mermaid diagrams of the documentation (see check_mermaid.mjs)",
+ "type": "module",
+ "dependencies": {
+ "jsdom": "30.1.1",
+ "mermaid": "11.17.2"
+ }
+}
diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp
index df5c88523..49b3c32e2 100644
--- a/include/nlohmann/detail/conversions/to_json.hpp
+++ b/include/nlohmann/detail/conversions/to_json.hpp
@@ -235,8 +235,11 @@ struct external_constructor
for (auto&& x : std::forward(arr))
{
j.m_data.m_value.array->push_back(x);
- j.set_parent(j.m_data.m_value.array->back());
}
+ // set the parents only once all elements are in place: a push_back
+ // that reallocates moves the earlier elements, which does not keep
+ // their parent pointers
+ j.set_parents();
j.assert_invariant();
}
#endif
diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp
index 9060d76a9..86f00bef6 100644
--- a/include/nlohmann/detail/input/binary_reader.hpp
+++ b/include/nlohmann/detail/input/binary_reader.hpp
@@ -614,13 +614,13 @@ class binary_reader
case 0x10: // int32
{
std::int32_t value{};
- return get_number(input_format_t::bson, value) && sax->number_integer(value);
+ return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value));
}
case 0x12: // int64
{
std::int64_t value{};
- return get_number(input_format_t::bson, value) && sax->number_integer(value);
+ return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value));
}
case 0x11: // uint64
@@ -659,7 +659,7 @@ class binary_reader
parse_error::create(112, chars_read,
exception_message(input_format_t::cbor, "negative integer overflow", "value"), nullptr));
}
- return sax->number_integer(static_cast(-1) - static_cast(number));
+ return sax->number_integer(conditional_static_cast(static_cast(-1) - static_cast(number)));
}
/*!
@@ -1905,25 +1905,25 @@ class binary_reader
case 0xD0: // int 8
{
std::int8_t number{};
- return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number));
}
case 0xD1: // int 16
{
std::int16_t number{};
- return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number));
}
case 0xD2: // int 32
{
std::int32_t number{};
- return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number));
}
case 0xD3: // int 64
{
std::int64_t number{};
- return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
+ return get_number(input_format_t::msgpack, number) && sax->number_integer(conditional_static_cast(number));
}
case 0xDC: // array 16
@@ -2980,25 +2980,25 @@ class binary_reader
case 'i':
{
std::int8_t number{};
- return get_number(input_format, number) && sax->number_integer(number);
+ return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number));
}
case 'I':
{
std::int16_t number{};
- return get_number(input_format, number) && sax->number_integer(number);
+ return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number));
}
case 'l':
{
std::int32_t number{};
- return get_number(input_format, number) && sax->number_integer(number);
+ return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number));
}
case 'L':
{
std::int64_t number{};
- return get_number(input_format, number) && sax->number_integer(number);
+ return get_number(input_format, number) && sax->number_integer(conditional_static_cast(number));
}
case 'u':
@@ -3558,7 +3558,7 @@ class binary_reader
// integer -1..-10
if (byte <= 0xC1)
{
- return sax->number_integer(-1 - static_cast(byte - 0xB8));
+ return sax->number_integer(conditional_static_cast(-1 - static_cast(byte - 0xB8)));
}
// 0xC2..0xF7: a UTF-8 lead byte begins a string if a continuation
@@ -3688,6 +3688,11 @@ class binary_reader
if (0xC2 <= byte && byte <= 0xF7)
{
const auto second = get_bon8();
+ if (second == char_traits::eof())
+ {
+ // the input ends inside a character or an integer
+ return unexpect_eof(input_format_t::bon8, "key");
+ }
unget_bon8(second);
if (is_bon8_continuation(second))
{
@@ -3786,6 +3791,12 @@ class binary_reader
// a lead byte ends the string if no continuation byte follows: it
// is then the first byte of an integer
const auto second = get_bon8();
+ if (second == char_traits::eof())
+ {
+ // the input ends inside a character or an integer: either
+ // way, the message is incomplete
+ return unexpect_eof(input_format_t::bon8, "string");
+ }
if (!is_bon8_continuation(second))
{
unget_bon8(second);
@@ -3866,6 +3877,8 @@ class binary_reader
template
bool get_to(T& dest, const input_format_t format, const char* context)
{
+ // false positive: new_chars_read is read on the next lines
+ // @infer-ignore DEAD_STORE
auto new_chars_read = ia.get_elements(&dest);
chars_read += new_chars_read;
if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T)))
@@ -4117,6 +4130,8 @@ class binary_reader
// resize() is required to make size() exactly old_size + wanted;
// that is the room get_elements() is allowed to write into
JSON_ASSERT(result.size() == old_size + wanted);
+ // false positive: bytes_read is read on the next lines
+ // @infer-ignore DEAD_STORE
const std::size_t bytes_read = ia.get_elements(&result[old_size], wanted);
chars_read += bytes_read;
if (JSON_HEDLEY_UNLIKELY(bytes_read < wanted))
diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp
index c2943f645..7998dc6dd 100644
--- a/include/nlohmann/detail/input/parser.hpp
+++ b/include/nlohmann/detail/input/parser.hpp
@@ -54,8 +54,9 @@ using parser_callback_t =
/*!
@brief syntax analysis
-This class implements an iterative parser that keeps the open containers on
-an explicit stack and reports what it reads as SAX events.
+This class implements a parser for JSON text. Nested arrays and objects are tracked with an explicit
+stack instead of recursion, so deeply nested input does not exhaust the call stack, and what is read
+is reported as SAX events.
*/
template
class parser
diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp
index ecb85c931..6b056dae4 100644
--- a/include/nlohmann/detail/json_pointer.hpp
+++ b/include/nlohmann/detail/json_pointer.hpp
@@ -85,7 +85,7 @@ class json_pointer
}
/// @brief return a string representation of the JSON pointer
- /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
+ /// @sa https://json.nlohmann.me/api/json_pointer/operator_string_t/
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
operator string_t() const
{
@@ -94,7 +94,7 @@ class json_pointer
#ifndef JSON_NO_IO
/// @brief write string representation of the JSON pointer to stream
- /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+ /// @sa https://json.nlohmann.me/api/operator_ltlt/
friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
{
o << ptr.to_string();
@@ -1106,7 +1106,8 @@ class json_pointer
friend bool operator!=(const StringType& lhs,
const json_pointer& rhs);
- /// @brief compares two JSON pointer for less-than
+ /// @brief compares two JSON pointers for less-than
+ /// @sa https://json.nlohmann.me/api/json_pointer/operator_spaceship/
template
// NOLINTNEXTLINE(readability-redundant-declaration)
friend bool operator<(const json_pointer& lhs,
diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp
index 8850ca959..3a5f7e606 100644
--- a/include/nlohmann/detail/macro_scope.hpp
+++ b/include/nlohmann/detail/macro_scope.hpp
@@ -298,7 +298,7 @@ void templated_json_throw(ExceptionType exception)
@brief macro to briefly define a mapping between an enum and JSON with exception
on invalid input
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
-@since version 3.12.0
+@since version 3.13.0
*/
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
template \
diff --git a/include/nlohmann/detail/string_utils.hpp b/include/nlohmann/detail/string_utils.hpp
index 2495c5802..7c40f7395 100644
--- a/include/nlohmann/detail/string_utils.hpp
+++ b/include/nlohmann/detail/string_utils.hpp
@@ -57,7 +57,7 @@ inline std::string hex_byte(const std::uint8_t byte)
Used to turn a decoded code point back into bytes: by the wide-string input
adapters in input_adapters.hpp (one code point per UTF-32 unit, per UTF-16
unit outside the surrogate range, and per valid UTF-16 surrogate pair), and
-by the lexer's `\uXXXX`/`\uXXXX\uYYYY` handling in lexer.hpp. Passing a
+by the lexer's handling of u-escapes and surrogate pairs in lexer.hpp. Passing a
code point above U+10FFFF, or one in the surrogate range U+D800..U+DFFF, is
undefined behavior; callers are expected to have rejected those already
(the wide-string adapters pass malformed units through unencoded instead of
@@ -70,7 +70,7 @@ reaching it).
@param[in] out called once for each byte of the UTF-8 encoding of @a cp
*/
template
-void encode_utf8(std::uint32_t cp, Out&& out)
+void encode_utf8(std::uint32_t cp, const Out& out)
{
JSON_ASSERT(cp <= 0x10FFFF);
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index 8f1756f56..d588dae74 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -2561,6 +2561,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
{
auto ret = ValueType();
JSONSerializer::from_json(*this, ret);
+ // false positive: ret is returned by value, not its address
+ // @infer-ignore STACK_VARIABLE_ADDRESS_ESCAPE
return ret;
}
@@ -5129,7 +5131,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
/// @{
#ifndef JSON_NO_IO
/// @brief serialize to stream
- /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+ /// @sa https://json.nlohmann.me/api/operator_ltlt/
friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
{
// read width member and use it as the indentation parameter if nonzero
@@ -5148,7 +5150,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
}
/// @brief serialize to stream
- /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
+ /// @sa https://json.nlohmann.me/api/operator_ltlt/
/// @deprecated This function is deprecated since 3.0.0 and will be removed in
/// version 4.0.0 of the library. Please use
/// operator<<(std::ostream&, const basic_json&) instead; that is,
@@ -5317,7 +5319,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
#endif
#ifndef JSON_NO_IO
/// @brief deserialize from stream
- /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
+ /// @sa https://json.nlohmann.me/api/operator_gtgt/
/// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
/// version 4.0.0 of the library. Please use
/// operator>>(std::istream&, basic_json&) instead; that is,
@@ -5329,7 +5331,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
}
/// @brief deserialize from stream
- /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
+ /// @sa https://json.nlohmann.me/api/operator_gtgt/
friend std::istream& operator>>(std::istream& i, basic_json& j)
{
// parse into a temporary so that j is left unchanged if parsing fails
@@ -6503,6 +6505,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
// Any other object type places its members itself - std::map
// in key order, a hash map in an order its operator== ignores -
// so a member-by-member diff always reproduces target there.
+#ifdef JSON_HEDLEY_MSVC_VERSION
+#pragma warning(push )
+#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
+#endif
if (!detail::is_ordered_map::value
|| (common_keys_source_order == common_keys_target_order && new_keys_form_suffix))
{
@@ -6513,6 +6519,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
common_keys = std::move(common_keys_source_order);
return true;
}
+#ifdef JSON_HEDLEY_MSVC_VERSION
+#pragma warning( pop )
+#endif
// slow path: the common keys are in a different relative
// order in source and target (only possible for a
@@ -7009,10 +7018,10 @@ struct formatter // NOLINT(cert-dcl58-c
int indent = -1;
char indent_char = ' ';
- constexpr auto parse(format_parse_context& ctx) -> format_parse_context::iterator
+ constexpr format_parse_context::iterator parse(format_parse_context& ctx)
{
- auto it = ctx.begin();
- const auto end = ctx.end();
+ format_parse_context::iterator it = ctx.begin();
+ const format_parse_context::iterator end = ctx.end();
constexpr auto is_align = [](char c)
{
return c == '<' || c == '>' || c == '^';
diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp
index 7b6f63781..656f24264 100644
--- a/include/nlohmann/ordered_map.hpp
+++ b/include/nlohmann/ordered_map.hpp
@@ -12,12 +12,13 @@
#include // equal_to, less
#include // initializer_list
#include // input_iterator_tag, iterator_traits
+#include // allocator
#include // for operator new (placement new)
#include // for out_of_range
#include // forward_as_tuple
#include // enable_if, integral_constant, is_convertible, is_nothrow_move_constructible
#include // forward, move, pair, piecewise_construct
-#include // vector, allocator
+#include // vector
#include
#include
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index f225fd255..bdfb3f0c8 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -2710,7 +2710,7 @@ void templated_json_throw(ExceptionType exception)
@brief macro to briefly define a mapping between an enum and JSON with exception
on invalid input
@def NLOHMANN_JSON_SERIALIZE_ENUM_STRICT
-@since version 3.12.0
+@since version 3.13.0
*/
#define NLOHMANN_JSON_SERIALIZE_ENUM_STRICT(ENUM_TYPE, ...) \
template \
@@ -6294,7 +6294,7 @@ inline std::string hex_byte(const std::uint8_t byte)
Used to turn a decoded code point back into bytes: by the wide-string input
adapters in input_adapters.hpp (one code point per UTF-32 unit, per UTF-16
unit outside the surrogate range, and per valid UTF-16 surrogate pair), and
-by the lexer's `\uXXXX`/`\uXXXX\uYYYY` handling in lexer.hpp. Passing a
+by the lexer's handling of u-escapes and surrogate pairs in lexer.hpp. Passing a
code point above U+10FFFF, or one in the surrogate range U+D800..U+DFFF, is
undefined behavior; callers are expected to have rejected those already
(the wide-string adapters pass malformed units through unencoded instead of
@@ -6307,7 +6307,7 @@ reaching it).
@param[in] out called once for each byte of the UTF-8 encoding of @a cp
*/
template
-void encode_utf8(std::uint32_t cp, Out&& out)
+void encode_utf8(std::uint32_t cp, const Out& out)
{
JSON_ASSERT(cp <= 0x10FFFF);
@@ -6881,8 +6881,11 @@ struct external_constructor
for (auto&& x : std::forward(arr))
{
j.m_data.m_value.array->push_back(x);
- j.set_parent(j.m_data.m_value.array->back());
}
+ // set the parents only once all elements are in place: a push_back
+ // that reallocates moves the earlier elements, which does not keep
+ // their parent pointers
+ j.set_parents();
j.assert_invariant();
}
#endif
@@ -14637,13 +14640,13 @@ class binary_reader
case 0x10: // int32
{
std::int32_t value{};
- return get_number(input_format_t::bson, value) && sax->number_integer(value);
+ return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value));
}
case 0x12: // int64
{
std::int64_t value{};
- return get_number(input_format_t::bson, value) && sax->number_integer(value);
+ return get_number(input_format_t::bson, value) && sax->number_integer(conditional_static_cast(value));
}
case 0x11: // uint64
@@ -14682,7 +14685,7 @@ class binary_reader
parse_error::create(112, chars_read,
exception_message(input_format_t::cbor, "negative integer overflow", "value"), nullptr));
}
- return sax->number_integer(static_cast(-1) - static_cast(number));
+ return sax->number_integer(conditional_static_cast(static_cast