From 526b6d3fd6e4709e64b1b0e8d67ac8fded4410e5 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 29 Sep 2026 17:05:35 +0200 Subject: [PATCH] Review and extend the documentation, and check it in CI A review of all documentation pages found factual errors, dead links, missing cross-references, and gaps in examples. This fixes them and adds checks so the same problems are caught automatically. Fixes: - wrong signatures and version histories (operator!= C++20 member, binary() subtype type, get(), JSON_NO_THREAD_LOCAL, ...) - stale descriptions (number parsing since #5283, UBJSON table, SAX example that no longer compiled, tsl::ordered_map advice) - dead internal and external links; repology.org badges (the domain is suspended) replaced by badges that query the registries directly - deprecation notes link the migration guide; the guide itself fixed Additions: - "See also" sections, cross-references, 25 runnable examples, 12 Mermaid diagrams, new API pages for json_pointer::operator<=> and byte_container_with_subtype::operator==/!= - landing page, guides for untrusted input and performance - "unreleased" badge after versions newer than the latest release Checks: - strict documentation build (broken links/anchors fail it); CI and the publish workflow fetch the full history the build needs - weekly external link check, Mermaid syntax check in CI - check_structure.py: example titles, heading levels, alt texts, header links, docset index coverage; its unused-example check works again - all examples produce the same output on every platform Signed-off-by: Niels Lohmann --- .github/CONTRIBUTING.md | 10 + .github/dependabot.yml | 11 + .github/workflows/check_docs_links.yml | 46 + .github/workflows/publish_documentation.yml | 4 + .github/workflows/ubuntu.yml | 8 +- .gitignore | 2 + README.md | 1 - cmake/ci.cmake | 6 + docs/Makefile | 5 +- docs/docset/docSet.sql | 35 + docs/mkdocs/Makefile | 13 +- docs/mkdocs/docs/api/basic_json/accept.md | 19 +- docs/mkdocs/docs/api/basic_json/array_t.md | 13 +- docs/mkdocs/docs/api/basic_json/at.md | 14 + docs/mkdocs/docs/api/basic_json/basic_json.md | 48 +- docs/mkdocs/docs/api/basic_json/begin.md | 8 + docs/mkdocs/docs/api/basic_json/binary.md | 13 +- docs/mkdocs/docs/api/basic_json/binary_t.md | 10 +- docs/mkdocs/docs/api/basic_json/boolean_t.md | 8 +- docs/mkdocs/docs/api/basic_json/cbegin.md | 7 + .../docs/api/basic_json/cbor_tag_handler_t.md | 6 + docs/mkdocs/docs/api/basic_json/cend.md | 7 + docs/mkdocs/docs/api/basic_json/clear.md | 5 + docs/mkdocs/docs/api/basic_json/contains.md | 12 + docs/mkdocs/docs/api/basic_json/crbegin.md | 7 + docs/mkdocs/docs/api/basic_json/crend.md | 7 + .../basic_json/default_object_comparator_t.md | 5 + docs/mkdocs/docs/api/basic_json/emplace.md | 3 +- .../docs/api/basic_json/emplace_back.md | 5 + docs/mkdocs/docs/api/basic_json/empty.md | 5 + docs/mkdocs/docs/api/basic_json/end.md | 7 + .../docs/api/basic_json/error_handler_t.md | 5 + docs/mkdocs/docs/api/basic_json/flatten.md | 17 +- docs/mkdocs/docs/api/basic_json/from_bson.md | 2 + docs/mkdocs/docs/api/basic_json/from_cbor.md | 2 + .../docs/api/basic_json/from_msgpack.md | 2 + .../mkdocs/docs/api/basic_json/from_ubjson.md | 2 + docs/mkdocs/docs/api/basic_json/get.md | 32 +- .../docs/api/basic_json/get_allocator.md | 13 + docs/mkdocs/docs/api/basic_json/get_to.md | 9 +- .../docs/api/basic_json/input_format_t.md | 5 + docs/mkdocs/docs/api/basic_json/insert.md | 12 +- docs/mkdocs/docs/api/basic_json/is_array.md | 7 + docs/mkdocs/docs/api/basic_json/is_binary.md | 6 + docs/mkdocs/docs/api/basic_json/is_boolean.md | 5 + .../docs/api/basic_json/is_discarded.md | 18 +- docs/mkdocs/docs/api/basic_json/is_null.md | 7 + docs/mkdocs/docs/api/basic_json/is_object.md | 7 + docs/mkdocs/docs/api/basic_json/is_string.md | 6 + docs/mkdocs/docs/api/basic_json/items.md | 2 + .../docs/api/basic_json/json_base_class_t.md | 8 +- .../docs/api/basic_json/json_serializer.md | 11 +- docs/mkdocs/docs/api/basic_json/max_size.md | 6 + .../mkdocs/docs/api/basic_json/merge_patch.md | 4 + .../docs/api/basic_json/number_float_t.md | 15 +- .../docs/api/basic_json/number_integer_t.md | 15 +- .../docs/api/basic_json/number_unsigned_t.md | 15 +- .../api/basic_json/object_comparator_t.md | 5 + docs/mkdocs/docs/api/basic_json/object_t.md | 21 +- docs/mkdocs/docs/api/basic_json/operator+=.md | 6 + docs/mkdocs/docs/api/basic_json/operator[].md | 12 + .../docs/api/basic_json/operator_ValueType.md | 9 +- .../mkdocs/docs/api/basic_json/operator_eq.md | 4 +- .../mkdocs/docs/api/basic_json/operator_ge.md | 10 + .../mkdocs/docs/api/basic_json/operator_le.md | 10 + .../mkdocs/docs/api/basic_json/operator_ne.md | 33 +- .../docs/api/basic_json/operator_value_t.md | 5 + docs/mkdocs/docs/api/basic_json/parse.md | 20 +- .../docs/api/basic_json/parse_event_t.md | 15 + .../docs/api/basic_json/parser_callback_t.md | 4 +- docs/mkdocs/docs/api/basic_json/patch.md | 17 +- .../docs/api/basic_json/patch_inplace.md | 18 +- docs/mkdocs/docs/api/basic_json/push_back.md | 6 + docs/mkdocs/docs/api/basic_json/rbegin.md | 7 + docs/mkdocs/docs/api/basic_json/rend.md | 7 + docs/mkdocs/docs/api/basic_json/sax_parse.md | 2 + docs/mkdocs/docs/api/basic_json/size.md | 5 + docs/mkdocs/docs/api/basic_json/std_hash.md | 4 + docs/mkdocs/docs/api/basic_json/string_t.md | 18 +- docs/mkdocs/docs/api/basic_json/swap.md | 20 +- docs/mkdocs/docs/api/basic_json/to_bjdata.md | 19 +- docs/mkdocs/docs/api/basic_json/to_bon8.md | 17 +- docs/mkdocs/docs/api/basic_json/to_bson.md | 17 +- docs/mkdocs/docs/api/basic_json/to_msgpack.md | 17 +- docs/mkdocs/docs/api/basic_json/to_ubjson.md | 19 +- docs/mkdocs/docs/api/basic_json/type.md | 6 + docs/mkdocs/docs/api/basic_json/type_name.md | 5 + docs/mkdocs/docs/api/basic_json/update.md | 6 +- docs/mkdocs/docs/api/basic_json/value.md | 27 + docs/mkdocs/docs/api/basic_json/value_t.md | 18 + .../mkdocs/docs/api/basic_json/~basic_json.md | 5 + .../byte_container_with_subtype.md | 8 + .../clear_subtype.md | 6 + .../has_subtype.md | 6 + .../api/byte_container_with_subtype/index.md | 4 +- .../operator_eq.md | 48 + .../operator_ne.md | 47 + .../set_subtype.md | 6 + .../byte_container_with_subtype/subtype.md | 6 + docs/mkdocs/docs/api/json.md | 5 + docs/mkdocs/docs/api/json_pointer/back.md | 11 + docs/mkdocs/docs/api/json_pointer/empty.md | 6 + docs/mkdocs/docs/api/json_pointer/front.md | 10 + docs/mkdocs/docs/api/json_pointer/index.md | 22 +- .../docs/api/json_pointer/json_pointer.md | 13 + .../docs/api/json_pointer/operator_eq.md | 7 + .../docs/api/json_pointer/operator_ne.md | 7 + .../docs/api/json_pointer/operator_slash.md | 10 + .../docs/api/json_pointer/operator_slasheq.md | 12 + .../api/json_pointer/operator_spaceship.md | 74 + .../api/json_pointer/operator_string_t.md | 5 +- docs/mkdocs/docs/api/json_pointer/pop_back.md | 10 + .../mkdocs/docs/api/json_pointer/pop_front.md | 9 + .../mkdocs/docs/api/json_pointer/push_back.md | 11 + .../docs/api/json_pointer/push_front.md | 10 + docs/mkdocs/docs/api/json_pointer/string_t.md | 5 + .../mkdocs/docs/api/json_pointer/to_string.md | 13 + docs/mkdocs/docs/api/json_sax/binary.md | 6 + docs/mkdocs/docs/api/json_sax/boolean.md | 5 + docs/mkdocs/docs/api/json_sax/end_array.md | 5 + docs/mkdocs/docs/api/json_sax/end_object.md | 6 + docs/mkdocs/docs/api/json_sax/index.md | 21 + docs/mkdocs/docs/api/json_sax/key.md | 6 + docs/mkdocs/docs/api/json_sax/null.md | 5 + docs/mkdocs/docs/api/json_sax/number_float.md | 6 + .../docs/api/json_sax/number_integer.md | 6 + .../docs/api/json_sax/number_unsigned.md | 6 + docs/mkdocs/docs/api/json_sax/parse_error.md | 6 + docs/mkdocs/docs/api/json_sax/start_array.md | 5 + docs/mkdocs/docs/api/json_sax/start_object.md | 6 + docs/mkdocs/docs/api/json_sax/string.md | 5 + docs/mkdocs/docs/api/macros/index.md | 1 + docs/mkdocs/docs/api/macros/json_assert.md | 4 +- .../macros/json_brace_init_copy_semantics.md | 4 +- .../api/macros/json_diagnostic_positions.md | 4 +- .../docs/api/macros/json_diagnostics.md | 6 +- .../macros/json_disable_enum_serialization.md | 6 +- .../mkdocs/docs/api/macros/json_has_cpp_11.md | 7 + .../docs/api/macros/json_has_filesystem.md | 5 + .../mkdocs/docs/api/macros/json_has_ranges.md | 7 + .../docs/api/macros/json_has_static_rtti.md | 7 +- .../docs/api/macros/json_has_std_format.md | 4 + .../macros/json_has_three_way_comparison.md | 5 + docs/mkdocs/docs/api/macros/json_no_io.md | 5 + .../docs/api/macros/json_no_thread_local.md | 6 +- .../macros/json_precise_stream_position.md | 4 +- .../macros/json_skip_library_version_check.md | 11 +- .../json_skip_unsupported_compiler_check.md | 7 +- .../api/macros/json_strict_nul_handling.md | 5 +- .../docs/api/macros/json_use_global_udls.md | 6 +- .../macros/json_use_implicit_conversions.md | 2 + ...n_use_legacy_discarded_value_comparison.md | 2 + .../docs/api/macros/json_use_simdutf.md | 12 +- .../macros/nlohmann_define_derived_type.md | 2 +- .../macros/nlohmann_define_type_intrusive.md | 6 +- .../nlohmann_define_type_non_intrusive.md | 6 +- .../macros/nlohmann_define_type_with_names.md | 19 +- .../macros/nlohmann_json_serialize_enum.md | 4 +- .../nlohmann_json_serialize_enum_strict.md | 6 +- docs/mkdocs/docs/api/operator_gtgt.md | 2 + docs/mkdocs/docs/api/operator_literal_json.md | 5 +- .../docs/api/operator_literal_json_pointer.md | 5 +- docs/mkdocs/docs/api/operator_ltlt.md | 2 + docs/mkdocs/docs/api/ordered_map.md | 4 +- docs/mkdocs/docs/community/assurance_case.md | 11 + docs/mkdocs/docs/css/custom.css | 16 + .../docs/examples/accept__iterator_pair.cpp | 15 + .../examples/accept__iterator_pair.output | 1 + .../examples/basic_json__BasicJsonType.cpp | 22 + .../examples/basic_json__BasicJsonType.output | 3 + .../examples/basic_json__CompatibleType.cpp | 6 +- .../basic_json__CompatibleType.output | 4 +- ...ontainer_with_subtype__operator__equal.cpp | 23 + ...ainer_with_subtype__operator__equal.output | 4 + ...ainer_with_subtype__operator__notequal.cpp | 23 + ...er_with_subtype__operator__notequal.output | 4 + docs/mkdocs/docs/examples/flatten__empty.cpp | 23 + .../docs/examples/flatten__empty.output | 11 + .../docs/examples/get__BasicJsonType.cpp | 17 + .../docs/examples/get__BasicJsonType.output | 2 + .../docs/examples/get__ValueType_const.cpp | 4 +- .../docs/examples/get__ValueType_const.output | 8 +- docs/mkdocs/docs/examples/get_to.cpp | 4 +- docs/mkdocs/docs/examples/get_to.output | 8 +- .../docs/examples/is_discarded__parse.cpp | 22 + .../docs/examples/is_discarded__parse.output | 3 + ...json_pointer__operator_spaceship.c++20.cpp | 32 + ...n_pointer__operator_spaceship.c++20.output | 3 + .../docs/examples/operator__ValueType.cpp | 4 +- .../docs/examples/operator__ValueType.output | 8 +- docs/mkdocs/docs/examples/parse_event_t.cpp | 44 + .../mkdocs/docs/examples/parse_event_t.output | 10 + .../mkdocs/docs/examples/patch__exception.cpp | 36 + .../docs/examples/patch__exception.output | 6 + .../examples/patch_inplace__exception.cpp | 38 + .../examples/patch_inplace__exception.output | 5 + .../mkdocs/docs/examples/sax_no_exception.cpp | 40 + .../docs/examples/sax_no_exception.output | 5 + .../docs/examples/to_bjdata__exception.cpp | 20 + .../docs/examples/to_bjdata__exception.output | 1 + .../docs/examples/to_bon8__exception.cpp | 22 + .../docs/examples/to_bon8__exception.output | 1 + .../docs/examples/to_bson__exception.cpp | 23 + .../docs/examples/to_bson__exception.output | 1 + .../docs/examples/to_msgpack__exception.cpp | 20 + .../examples/to_msgpack__exception.output | 1 + .../docs/examples/to_ubjson__exception.cpp | 20 + .../docs/examples/to_ubjson__exception.output | 1 + .../mkdocs/docs/examples/value__exception.cpp | 33 + .../docs/examples/value__exception.output | 2 + docs/mkdocs/docs/features/arbitrary_types.md | 100 +- docs/mkdocs/docs/features/assertions.md | 8 +- .../docs/features/binary_formats/bjdata.md | 6 +- .../docs/features/binary_formats/bon8.md | 4 +- .../docs/features/binary_formats/bson.md | 4 +- .../docs/features/binary_formats/cbor.md | 4 +- .../features/binary_formats/messagepack.md | 4 +- .../docs/features/binary_formats/ubjson.md | 52 +- docs/mkdocs/docs/features/binary_values.md | 28 +- docs/mkdocs/docs/features/comments.md | 2 +- .../features/element_access/checked_access.md | 6 +- .../features/element_access/default_value.md | 6 +- .../docs/features/element_access/index.md | 18 +- .../element_access/unchecked_access.md | 15 +- docs/mkdocs/docs/features/enum_conversion.md | 37 +- docs/mkdocs/docs/features/index.md | 6 +- docs/mkdocs/docs/features/iterators.md | 20 +- docs/mkdocs/docs/features/json_patch.md | 33 +- docs/mkdocs/docs/features/json_pointer.md | 3 +- docs/mkdocs/docs/features/macros.md | 3 +- docs/mkdocs/docs/features/merge_patch.md | 14 +- docs/mkdocs/docs/features/object_order.md | 4 +- docs/mkdocs/docs/features/parsing/index.md | 11 + .../docs/features/parsing/parse_exceptions.md | 64 +- .../docs/features/parsing/parser_callbacks.md | 15 +- .../docs/features/parsing/untrusted_input.md | 163 ++ docs/mkdocs/docs/features/performance.md | 215 +++ docs/mkdocs/docs/features/serialization.md | 4 +- .../docs/features/types/number_handling.md | 21 +- .../features/types/template_parameters.md | 26 +- docs/mkdocs/docs/home/customers.md | 20 +- docs/mkdocs/docs/home/exceptions.md | 46 +- docs/mkdocs/docs/home/faq.md | 30 +- docs/mkdocs/docs/home/license.md | 2 +- docs/mkdocs/docs/home/releases.md | 5 + docs/mkdocs/docs/home/sponsors.md | 2 +- docs/mkdocs/docs/index.md | 111 +- .../docs/integration/bazel/MODULE.bazel | 2 +- docs/mkdocs/docs/integration/cmake.md | 25 +- docs/mkdocs/docs/integration/index.md | 32 +- .../docs/integration/migration_guide.md | 31 +- .../mkdocs/docs/integration/msys2/example.cpp | 10 + .../nuget/nuget-package-content.png | Bin 19422 -> 0 bytes .../nuget/nuget-project-changes.png | Bin 30826 -> 0 bytes .../nuget/nuget-project-makefile.png | Bin 55236 -> 0 bytes .../docs/integration/package_managers.md | 275 ++- docs/mkdocs/docs/integration/pkg-config.md | 3 + .../docs/integration/swift/Package.swift | 17 + .../mkdocs/docs/integration/swift/example.cpp | 10 + docs/mkdocs/hooks/unreleased_versions.py | 82 + docs/mkdocs/mkdocs.yml | 36 +- docs/mkdocs/scripts/check_structure.py | 114 +- docs/mkdocs/scripts/check_version_history.py | 102 ++ docs/mkdocs/scripts/mermaid/check_mermaid.mjs | 54 + docs/mkdocs/scripts/mermaid/package-lock.json | 1619 +++++++++++++++++ docs/mkdocs/scripts/mermaid/package.json | 10 + include/nlohmann/detail/input/parser.hpp | 3 +- include/nlohmann/detail/json_pointer.hpp | 7 +- include/nlohmann/detail/macro_scope.hpp | 2 +- include/nlohmann/json.hpp | 12 +- single_include/nlohmann/json.hpp | 24 +- 271 files changed, 5227 insertions(+), 608 deletions(-) create mode 100644 .github/workflows/check_docs_links.yml create mode 100644 docs/mkdocs/docs/api/byte_container_with_subtype/operator_eq.md create mode 100644 docs/mkdocs/docs/api/byte_container_with_subtype/operator_ne.md create mode 100644 docs/mkdocs/docs/api/json_pointer/operator_spaceship.md create mode 100644 docs/mkdocs/docs/examples/accept__iterator_pair.cpp create mode 100644 docs/mkdocs/docs/examples/accept__iterator_pair.output create mode 100644 docs/mkdocs/docs/examples/basic_json__BasicJsonType.cpp create mode 100644 docs/mkdocs/docs/examples/basic_json__BasicJsonType.output create mode 100644 docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.cpp create mode 100644 docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.output create mode 100644 docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.cpp create mode 100644 docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.output create mode 100644 docs/mkdocs/docs/examples/flatten__empty.cpp create mode 100644 docs/mkdocs/docs/examples/flatten__empty.output create mode 100644 docs/mkdocs/docs/examples/get__BasicJsonType.cpp create mode 100644 docs/mkdocs/docs/examples/get__BasicJsonType.output create mode 100644 docs/mkdocs/docs/examples/is_discarded__parse.cpp create mode 100644 docs/mkdocs/docs/examples/is_discarded__parse.output create mode 100644 docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.cpp create mode 100644 docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.output create mode 100644 docs/mkdocs/docs/examples/parse_event_t.cpp create mode 100644 docs/mkdocs/docs/examples/parse_event_t.output create mode 100644 docs/mkdocs/docs/examples/patch__exception.cpp create mode 100644 docs/mkdocs/docs/examples/patch__exception.output create mode 100644 docs/mkdocs/docs/examples/patch_inplace__exception.cpp create mode 100644 docs/mkdocs/docs/examples/patch_inplace__exception.output create mode 100644 docs/mkdocs/docs/examples/sax_no_exception.cpp create mode 100644 docs/mkdocs/docs/examples/sax_no_exception.output create mode 100644 docs/mkdocs/docs/examples/to_bjdata__exception.cpp create mode 100644 docs/mkdocs/docs/examples/to_bjdata__exception.output create mode 100644 docs/mkdocs/docs/examples/to_bon8__exception.cpp create mode 100644 docs/mkdocs/docs/examples/to_bon8__exception.output create mode 100644 docs/mkdocs/docs/examples/to_bson__exception.cpp create mode 100644 docs/mkdocs/docs/examples/to_bson__exception.output create mode 100644 docs/mkdocs/docs/examples/to_msgpack__exception.cpp create mode 100644 docs/mkdocs/docs/examples/to_msgpack__exception.output create mode 100644 docs/mkdocs/docs/examples/to_ubjson__exception.cpp create mode 100644 docs/mkdocs/docs/examples/to_ubjson__exception.output create mode 100644 docs/mkdocs/docs/examples/value__exception.cpp create mode 100644 docs/mkdocs/docs/examples/value__exception.output create mode 100644 docs/mkdocs/docs/features/parsing/untrusted_input.md create mode 100644 docs/mkdocs/docs/features/performance.md create mode 100644 docs/mkdocs/docs/integration/msys2/example.cpp delete mode 100644 docs/mkdocs/docs/integration/nuget/nuget-package-content.png delete mode 100644 docs/mkdocs/docs/integration/nuget/nuget-project-changes.png delete mode 100644 docs/mkdocs/docs/integration/nuget/nuget-project-makefile.png create mode 100644 docs/mkdocs/docs/integration/swift/Package.swift create mode 100644 docs/mkdocs/docs/integration/swift/example.cpp create mode 100644 docs/mkdocs/hooks/unreleased_versions.py create mode 100644 docs/mkdocs/scripts/check_version_history.py create mode 100644 docs/mkdocs/scripts/mermaid/check_mermaid.mjs create mode 100644 docs/mkdocs/scripts/mermaid/package-lock.json create mode 100644 docs/mkdocs/scripts/mermaid/package.json diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 4125b066a..6f3d0bef3 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -142,6 +142,16 @@ The documentation will then be available at . See the do [mkdocs](https://www.mkdocs.org) and [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) for more information. +Before opening a pull request, check the documentation like the CI does: + +```shell +make build -C docs/mkdocs # strict build: fails on broken links, anchors, and structure problems +make check_mermaid -C docs/mkdocs # checks the Mermaid diagrams (requires Node.js) +``` + +A new API page also needs an entry in [`docs/docset/docSet.sql`](https://github.com/nlohmann/json/blob/develop/docs/docset/docSet.sql), +the search index of the docset; `make build` reports missing entries. + ### Amalgamate the source code The single-header files diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ef1432591..ef185fbc2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -18,6 +18,17 @@ updates: cooldown: default-days: 7 + - package-ecosystem: npm + directory: /docs/mkdocs/scripts/mermaid + schedule: + interval: daily + cooldown: + default-days: 7 + ignore: + # Material for MkDocs loads mermaid@11; keep the checker on the same major version + - dependency-name: mermaid + update-types: ["version-update:semver-major"] + - package-ecosystem: pip directory: /tools/astyle schedule: diff --git a/.github/workflows/check_docs_links.yml b/.github/workflows/check_docs_links.yml new file mode 100644 index 000000000..342c96bff --- /dev/null +++ b/.github/workflows/check_docs_links.yml @@ -0,0 +1,46 @@ +name: Check documentation links + +# check the links of the documentation weekly; external links break without any change in this repository +on: + schedule: + - cron: '17 4 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + +jobs: + check_docs_links: + if: github.repository == 'nlohmann/json' + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Harden Runner + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 + with: + egress-policy: audit + + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Install virtual environment + run: make install_venv -C docs/mkdocs + + - name: Check links + shell: bash # adds -o pipefail, so tee does not hide the exit code + run: make link_check -C docs/mkdocs 2>&1 | tee link_check.log + + - name: Summarize broken links + if: failure() + run: | + { + echo '### Broken documentation links' + echo '```' + grep 'invalid url' link_check.log || true + echo '```' + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/publish_documentation.yml b/.github/workflows/publish_documentation.yml index 189d95419..6aea45ce0 100644 --- a/.github/workflows/publish_documentation.yml +++ b/.github/workflows/publish_documentation.yml @@ -31,6 +31,10 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # the git-revision-date-localized plugin needs the history for correct "last update" dates and so the + # strict build does not fail on a shallow clone + fetch-depth: 0 - name: Install virtual environment run: make install_venv -C docs/mkdocs diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d8c27c621..5764750eb 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -389,7 +389,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - target: [ci_test_examples, ci_test_build_documentation] + target: [ci_test_examples, ci_test_build_documentation, ci_test_documentation_mermaid] steps: - name: Harden Runner uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 @@ -399,6 +399,12 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false + # the git-revision-date-localized plugin needs the history; a shallow clone makes the strict build fail + fetch-depth: ${{ matrix.target == 'ci_test_build_documentation' && '0' || '1' }} + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + if: matrix.target == 'ci_test_documentation_mermaid' + with: + node-version: 24 - name: Run CMake run: cmake -S . -B build -DJSON_CI=On - name: Build diff --git a/.gitignore b/.gitignore index 03fe8147e..474b62347 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ /docs/docset/docSet.dsidx /docs/mkdocs/.cache/ /docs/mkdocs/docs/__pycache__/ +/docs/mkdocs/hooks/__pycache__/ +/docs/mkdocs/scripts/mermaid/node_modules/ /docs/mkdocs/site/ /docs/mkdocs/venv/ diff --git a/README.md b/README.md index cc3546686..ddfa48348 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/develop/LICENSE.MIT) [![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) -[![Packaging status](https://repology.org/badge/tiny-repos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) [![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases) [![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/nlohmann/json.svg)](https://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") diff --git a/cmake/ci.cmake b/cmake/ci.cmake index f7695c36e..c5fc4081f 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -849,6 +849,12 @@ add_custom_target(ci_test_build_documentation COMMENT "Build the documentation" ) +add_custom_target(ci_test_documentation_mermaid + COMMAND make check_mermaid + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/docs/mkdocs + COMMENT "Check the Mermaid diagrams of the documentation" +) + ############################################################################### # Clean up all generated files. ############################################################################### diff --git a/docs/Makefile b/docs/Makefile index 0412fb90a..42bb5e669 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -35,9 +35,10 @@ create_output: $(EXAMPLES:.cpp=.output) # check output of all stand-alone example files check_output: $(EXAMPLES:.cpp=.test) -# check output of all stand-alone example files (exclude files with platform-dependent output.) +# check output of all stand-alone example files (exclude files whose output depends on the platform by nature: +# library and compiler information, container size limits, and hash values) # This target is used in the CI (ci_test_documentation). -check_output_portable: $(filter-out mkdocs/docs/examples/meta.test mkdocs/docs/examples/max_size.test mkdocs/docs/examples/std_hash.test mkdocs/docs/examples/basic_json__CompatibleType.test,$(EXAMPLES:.cpp=.test)) +check_output_portable: $(filter-out mkdocs/docs/examples/meta.test mkdocs/docs/examples/max_size.test mkdocs/docs/examples/std_hash.test,$(EXAMPLES:.cpp=.test)) clean: rm -fr $(EXAMPLES:.cpp=) diff --git a/docs/docset/docSet.sql b/docs/docset/docSet.sql index 3a97e405f..7870db1b5 100644 --- a/docs/docset/docSet.sql +++ b/docs/docset/docSet.sql @@ -10,9 +10,12 @@ INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype', INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::byte_container_with_subtype', 'Constructor', 'api/byte_container_with_subtype/byte_container_with_subtype/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::clear_subtype', 'Method', 'api/byte_container_with_subtype/clear_subtype/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::has_subtype', 'Method', 'api/byte_container_with_subtype/has_subtype/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::operator!=', 'Operator', 'api/byte_container_with_subtype/operator_ne/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::operator==', 'Operator', 'api/byte_container_with_subtype/operator_eq/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::set_subtype', 'Method', 'api/byte_container_with_subtype/set_subtype/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('byte_container_with_subtype::subtype', 'Method', 'api/byte_container_with_subtype/subtype/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json', 'Class', 'api/basic_json/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('format_as', 'Function', 'api/basic_json/format_as/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::accept', 'Function', 'api/basic_json/accept/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::array', 'Function', 'api/basic_json/array/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('basic_json::array_t', 'Type', 'api/basic_json/array_t/index.html'); @@ -132,15 +135,19 @@ INSERT INTO searchIndex(name, type, path) VALUES ('json', 'Class', 'api/json/ind INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer', 'Class', 'api/json_pointer/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::back', 'Method', 'api/json_pointer/back/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::empty', 'Method', 'api/json_pointer/empty/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::front', 'Method', 'api/json_pointer/front/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::json_pointer', 'Constructor', 'api/json_pointer/json_pointer/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator==', 'Operator', 'api/json_pointer/operator_eq/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator!=', 'Operator', 'api/json_pointer/operator_ne/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator/', 'Operator', 'api/json_pointer/operator_slash/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator/=', 'Operator', 'api/json_pointer/operator_slasheq/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator string_t', 'Operator', 'api/json_pointer/operator_string_t/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::operator<=>', 'Operator', 'api/json_pointer/operator_spaceship/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::parent_pointer', 'Method', 'api/json_pointer/parent_pointer/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::pop_back', 'Method', 'api/json_pointer/pop_back/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::pop_front', 'Method', 'api/json_pointer/pop_front/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::push_back', 'Method', 'api/json_pointer/push_back/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::push_front', 'Method', 'api/json_pointer/push_front/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::string_t', 'Type', 'api/json_pointer/string_t/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_pointer::to_string', 'Method', 'api/json_pointer/to_string/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('json_sax', 'Class', 'api/json_sax/index.html'); @@ -163,6 +170,7 @@ INSERT INTO searchIndex(name, type, path) VALUES ('operator<<', 'Operator', 'api INSERT INTO searchIndex(name, type, path) VALUES ('operator>>', 'Operator', 'api/operator_gtgt/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_json', 'Class', 'api/ordered_json/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('ordered_map', 'Class', 'api/ordered_map/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('std::formatter', 'Class', 'api/basic_json/std_formatter/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('std::hash', 'Class', 'api/basic_json/std_hash/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('std::swap', 'Function', 'api/basic_json/std_swap/index.html'); @@ -195,17 +203,20 @@ INSERT INTO searchIndex(name, type, path) VALUES ('nlohmann Namespace', 'Guide', INSERT INTO searchIndex(name, type, path) VALUES ('Types', 'Guide', 'features/types/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Types: Number Handling', 'Guide', 'features/types/number_handling/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Object Order', 'Guide', 'features/object_order/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('Performance', 'Guide', 'features/performance/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Parsing', 'Guide', 'features/parsing/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: JSON Lines', 'Guide', 'features/parsing/json_lines/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Parser Callbacks', 'Guide', 'features/parsing/parser_callbacks/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Parsing and Exceptions', 'Guide', 'features/parsing/parse_exceptions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: SAX Interface', 'Guide', 'features/parsing/sax_interface/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('Parsing: Untrusted Input', 'Guide', 'features/parsing/untrusted_input/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Runtime Assertions', 'Guide', 'features/assertions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Specializing enum conversion', 'Guide', 'features/enum_conversion/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Supported Macros', 'Guide', 'features/macros/index.html'); -- Macros INSERT INTO searchIndex(name, type, path) VALUES ('JSON_ASSERT', 'Macro', 'api/macros/json_assert/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_BRACE_INIT_COPY_SEMANTICS', 'Macro', 'api/macros/json_brace_init_copy_semantics/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_CATCH_USER', 'Macro', 'api/macros/json_throw_user/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTICS', 'Macro', 'api/macros/json_diagnostics/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_DIAGNOSTIC_POSITIONS', 'Macro', 'api/macros/json_diagnostic_positions/index.html'); @@ -214,34 +225,58 @@ INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_11', 'Macro', 'a INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_14', 'Macro', 'api/macros/json_has_cpp_11/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_17', 'Macro', 'api/macros/json_has_cpp_11/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_20', 'Macro', 'api/macros/json_has_cpp_11/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_23', 'Macro', 'api/macros/json_has_cpp_11/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_CPP_26', 'Macro', 'api/macros/json_has_cpp_11/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_EXPERIMENTAL_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_FILESYSTEM', 'Macro', 'api/macros/json_has_filesystem/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_RANGES', 'Macro', 'api/macros/json_has_ranges/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STATIC_RTTI', 'Macro', 'api/macros/json_has_static_rtti/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_STD_FORMAT', 'Macro', 'api/macros/json_has_std_format/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_HAS_THREE_WAY_COMPARISON', 'Macro', 'api/macros/json_has_three_way_comparison/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NOEXCEPTION', 'Macro', 'api/macros/json_noexception/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_IO', 'Macro', 'api/macros/json_no_io/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_NO_THREAD_LOCAL', 'Macro', 'api/macros/json_no_thread_local/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_PRECISE_STREAM_POSITION', 'Macro', 'api/macros/json_precise_stream_position/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_SKIP_LIBRARY_VERSION_CHECK', 'Macro', 'api/macros/json_skip_library_version_check/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_SKIP_UNSUPPORTED_COMPILER_CHECK', 'Macro', 'api/macros/json_skip_unsupported_compiler_check/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_STRICT_NUL_HANDLING', 'Macro', 'api/macros/json_strict_nul_handling/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_THROW_USER', 'Macro', 'api/macros/json_throw_user/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_TRY_USER', 'Macro', 'api/macros/json_throw_user/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_GLOBAL_UDLS', 'Macro', 'api/macros/json_use_global_udls/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_IMPLICIT_CONVERSIONS', 'Macro', 'api/macros/json_use_implicit_conversions/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON', 'Macro', 'api/macros/json_use_legacy_discarded_value_comparison/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('JSON_USE_SIMDUTF', 'Macro', 'api/macros/json_use_simdutf/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('Macros', 'Macro', 'api/macros/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_derived_type/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_intrusive/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT', 'Macro', 'api/macros/nlohmann_define_type_non_intrusive/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES', 'Macro', 'api/macros/nlohmann_define_type_with_names/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE', 'Macro', 'api/macros/nlohmann_json_namespace/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_BEGIN', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_END', 'Macro', 'api/macros/nlohmann_json_namespace_begin/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_NAMESPACE_NO_VERSION', 'Macro', 'api/macros/nlohmann_json_namespace_no_version/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM', 'Macro', 'api/macros/nlohmann_json_serialize_enum/index.html'); +INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_SERIALIZE_ENUM_STRICT', 'Macro', 'api/macros/nlohmann_json_serialize_enum_strict/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MAJOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_MINOR', 'Macro', 'api/macros/nlohmann_json_version_major/index.html'); INSERT INTO searchIndex(name, type, path) VALUES ('NLOHMANN_JSON_VERSION_PATCH', 'Macro', 'api/macros/nlohmann_json_version_major/index.html'); diff --git a/docs/mkdocs/Makefile b/docs/mkdocs/Makefile index 8c72b0e80..55ee0d509 100644 --- a/docs/mkdocs/Makefile +++ b/docs/mkdocs/Makefile @@ -1,3 +1,8 @@ +# The MkDocs 2.0 banners of Material for MkDocs and ProperDocs (via mkdocs-redirects) are printed to stderr, not +# logged, so they do not affect --strict; silence them anyway. +export NO_MKDOCS_2_WARNING := true +export DISABLE_MKDOCS_2_WARNING := true + # serve the site locally serve: style_check venv/bin/mkdocs serve @@ -8,11 +13,17 @@ serve_dirty: style_check # This target is used in the CI (ci_test_build_documentation). # This target is used by the docset Makefile. build: style_check - venv/bin/mkdocs build + venv/bin/mkdocs build --strict style_check: @cd docs ; ../venv/bin/python3 ../scripts/check_structure.py +# check that all Mermaid diagrams parse (needs Node.js) +# This target is used in the CI (ci_test_documentation_mermaid). +check_mermaid: + npm ci --prefix scripts/mermaid --ignore-scripts --no-audit --no-fund + node scripts/mermaid/check_mermaid.mjs docs + # check the links in the documentation files in docs/mkdocs link_check: ENABLED_HTMLPROOFER=true venv/bin/mkdocs build diff --git a/docs/mkdocs/docs/api/basic_json/accept.md b/docs/mkdocs/docs/api/basic_json/accept.md index 0cdcae3a8..89111f69d 100644 --- a/docs/mkdocs/docs/api/basic_json/accept.md +++ b/docs/mkdocs/docs/api/basic_json/accept.md @@ -96,7 +96,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by ## Examples -??? example +??? example "Example: (1) reading from a string" The example below demonstrates the `accept()` function reading from a string. @@ -110,6 +110,21 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/accept__string.output" ``` +??? example "Example: (2) reading from an iterator pair" + + The example below demonstrates the `accept()` function reading from an iterator pair. Only the first call covers + exactly the JSON text; the second one also covers the trailing bytes and is therefore rejected. + + ```cpp + --8<-- "examples/accept__iterator_pair.cpp" + ``` + + Output: + + ```json + --8<-- "examples/accept__iterator_pair.output" + ``` + ## See also - [parse](parse.md) - deserialize from a compatible input @@ -137,3 +152,5 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/array_t.md b/docs/mkdocs/docs/api/basic_json/array_t.md index b6e41a6ad..caa0e9162 100644 --- a/docs/mkdocs/docs/api/basic_json/array_t.md +++ b/docs/mkdocs/docs/api/basic_json/array_t.md @@ -25,7 +25,7 @@ To store objects in C++, a type is defined by the template parameters explained ## Notes -#### Default type +### Default type With the default values for `ArrayType` (`std::vector`) and `AllocatorType` (`std::allocator`), the default value for `array_t` is: @@ -37,7 +37,7 @@ std::vector< > ``` -#### Limits +### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the maximum depth of nesting. @@ -46,7 +46,7 @@ In this class, the array's limit of nesting is not explicitly constrained. Howev introduced by the compiler or runtime environment. A theoretical limit can be queried by calling the [`max_size`](max_size.md) function of a JSON array. -#### Storage +### Storage Arrays are stored as pointers in a `basic_json` type. That is, for any access to array values, a pointer of type `#!cpp array_t*` must be dereferenced. @@ -67,6 +67,13 @@ Arrays are stored as pointers in a `basic_json` type. That is, for any access to --8<-- "examples/array_t.output" ``` +## See also + +- [object_t](object_t.md) the type used to store JSON objects +- [binary_t](binary_t.md) the type used to store binary values +- [is_array](is_array.md) checks whether the JSON value is an array +- [max_size](max_size.md) returns the maximum possible number of elements + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/at.md b/docs/mkdocs/docs/api/basic_json/at.md index 2d1042cc8..60daf38e3 100644 --- a/docs/mkdocs/docs/api/basic_json/at.md +++ b/docs/mkdocs/docs/api/basic_json/at.md @@ -92,6 +92,20 @@ Strong exception safety: if an exception occurs, the original value stays intact 3. Logarithmic in the size of the container. 4. Logarithmic in the size of the container. +## Notes + +!!! warning "Deprecation" + + Overload (4) also accepts a [`json_pointer`](../json_pointer/index.md) whose template argument is a `basic_json` + specialization (e.g., `nlohmann::json_pointer`) instead of a string type. This is deprecated since + version 3.11.0 and will be removed in a future major version; use `basic_json::json_pointer` (for `json`, + `nlohmann::json_pointer`) instead. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. + + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example "Example: (1) access specified array element with bounds checking" diff --git a/docs/mkdocs/docs/api/basic_json/basic_json.md b/docs/mkdocs/docs/api/basic_json/basic_json.md index 6aaab23c9..39099cf2f 100644 --- a/docs/mkdocs/docs/api/basic_json/basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/basic_json.md @@ -99,6 +99,25 @@ basic_json(basic_json&& other) noexcept; elements of the pairs are treated as keys and the second elements are as values. 3. In all other cases, an array is created. + The following flowchart also takes into account what happens when `type_deduction` is `#!cpp false`, in which case + `manual_type` decides between object and array, and an object can only be forced if `init` actually matches rule 2 + (or is empty): + + ```mermaid + flowchart TD + A(["initializer_list init"]) --> B{"empty, or every element is a 2-element
array whose first element is a string?"} + B -->|"yes"| C{"type_deduction"} + B -->|"no"| D{"type_deduction"} + C -->|"true"| OBJ["create object"] + C -->|"false"| E{"manual_type"} + E -->|"object"| OBJ + E -->|"array"| ARR["create array"] + D -->|"true"| ARR + D -->|"false"| F{"manual_type"} + F -->|"array"| ARR + F -->|"object"| ERR["throw type_error.301"] + ``` + The rules aim to create the best fit between a C++ initializer list and JSON values. The rationale is as follows: 1. The empty initializer list is written as `#!cpp {}` which is exactly an empty JSON object. @@ -169,8 +188,8 @@ basic_json(basic_json&& other) noexcept; - `BasicJsonType` has different template arguments than `basic_json_t`. **Note:** For cross-`basic_json` conversions to produce correct results, the target `basic_json`'s - `object_t::key_type` and `string_t` must be directly constructible from the source `basic_json`'s - corresponding types. See the description of overload (4) above for details on what happens when + [`object_t`](object_t.md)`::key_type` and [`string_t`](string_t.md) must be directly constructible from the source + `basic_json`'s corresponding types. See the description of overload (4) above for details on what happens when this requirement is not met. `U`: @@ -345,6 +364,22 @@ basic_json(basic_json&& other) noexcept; Note the output is platform-dependent. +??? example "Example: (4) create a JSON value from another `basic_json` specialization" + + The example below shows how a `json` value is converted to an `ordered_json` value and back using the converting + constructor. Note how the original insertion order of `oj` is not restored, because it was already given up when + converting to `json`, whose `object_t` sorts by key. + + ```cpp + --8<-- "examples/basic_json__BasicJsonType.cpp" + ``` + + Output: + + ```json + --8<-- "examples/basic_json__BasicJsonType.output" + ``` + ??? example "Example: (5) create a container (array or object) from an initializer list" The example below shows how JSON values are created from initializer lists. @@ -415,6 +450,15 @@ basic_json(basic_json&& other) noexcept; --8<-- "examples/basic_json__moveconstructor.output" ``` +## See also + +- [array](array.md) create a JSON array value, forcing array creation from an initializer list even when it looks like + an object +- [object](object.md) create a JSON object value, forcing object creation from an initializer list +- [binary](binary.md) create a JSON binary array value +- [operator=](operator=.md) copy assignment operator +- [Creating JSON values](../../features/creating_values.md) - the article on creating JSON values + ## Version history 1. Since version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/begin.md b/docs/mkdocs/docs/api/basic_json/begin.md index ef623a5ff..24671cee1 100644 --- a/docs/mkdocs/docs/api/basic_json/begin.md +++ b/docs/mkdocs/docs/api/basic_json/begin.md @@ -37,6 +37,14 @@ Constant. --8<-- "examples/begin.output" ``` +## See also + +- [end](end.md) returns an iterator to one past the last element +- [cbegin](cbegin.md) returns a const iterator to the first element +- [rbegin](rbegin.md) returns a reverse iterator to the last element +- [items](items.md) returns an iteration proxy to access keys and values during range-based for loops +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/binary.md b/docs/mkdocs/docs/api/basic_json/binary.md index efd4347ca..b19b0af27 100644 --- a/docs/mkdocs/docs/api/basic_json/binary.md +++ b/docs/mkdocs/docs/api/basic_json/binary.md @@ -7,9 +7,9 @@ static basic_json binary(typename binary_t::container_type&& init); // (2) static basic_json binary(const typename binary_t::container_type& init, - std::uint8_t subtype); + typename binary_t::subtype_type subtype); static basic_json binary(typename binary_t::container_type&& init, - std::uint8_t subtype); + typename binary_t::subtype_type subtype); ``` 1. Creates a JSON binary array value from a given binary container. @@ -61,6 +61,15 @@ initialization of a binary array type, for backwards compatibility and so it doe --8<-- "examples/binary.output" ``` +## See also + +- [binary_t](binary_t.md) type for binary values +- [get_binary](get_binary.md) get a reference to the stored binary value +- [is_binary](is_binary.md) return whether the value is binary +- [byte_container_with_subtype](../byte_container_with_subtype/index.md) container for binary values with subtype +- [Binary Values](../../features/binary_values.md) - the article on binary values + ## Version history - Added in version 3.8.0. +- Changed the type of `subtype` from `std::uint8_t` to `binary_t::subtype_type` (`std::uint64_t`) in version 3.10.0. diff --git a/docs/mkdocs/docs/api/basic_json/binary_t.md b/docs/mkdocs/docs/api/basic_json/binary_t.md index 36600748a..46b0f7ae2 100644 --- a/docs/mkdocs/docs/api/basic_json/binary_t.md +++ b/docs/mkdocs/docs/api/basic_json/binary_t.md @@ -48,16 +48,16 @@ represent a byte array in modern C++. ## Notes -#### Default type +### Default type The default values for `BinaryType` is `#!cpp std::vector`. -#### Supported byte types +### Supported byte types `#!cpp std::vector`, `#!cpp std::vector`, and `#!cpp std::vector` are supported. Regardless of which of them is configured, [`dump`](dump.md) writes the bytes as the numbers 0..255. -#### Custom BinaryType behavior +### Custom BinaryType behavior When a custom `BinaryType` is configured (other than the default `#!cpp std::vector`), you can assign values of that type directly to a `basic_json` instance, and they will automatically be recognized as binary values @@ -89,12 +89,12 @@ assert(extracted == data); This automatic type detection is a convenience feature that only applies to custom (non-default) `BinaryType` configurations. The default `nlohmann::json` continues to treat `#!cpp std::vector` as arrays for backward compatibility. -#### Storage +### Storage Binary Arrays are stored as pointers in a `basic_json` type. That is, for any access to array values, a pointer of the type `#!cpp binary_t*` must be dereferenced. -#### Notes on subtypes +### Notes on subtypes - CBOR - Binary values are represented as byte strings. Subtypes are written as tags. diff --git a/docs/mkdocs/docs/api/basic_json/boolean_t.md b/docs/mkdocs/docs/api/basic_json/boolean_t.md index bfb8c3426..f79a7622e 100644 --- a/docs/mkdocs/docs/api/basic_json/boolean_t.md +++ b/docs/mkdocs/docs/api/basic_json/boolean_t.md @@ -21,11 +21,11 @@ To store boolean values in C++, a type is defined by the template parameter `Bo ## Notes -#### Default type +### Default type With the default values for `BooleanType` (`#!cpp bool`), the default value for `boolean_t` is `#!cpp bool`. -#### Storage +### Storage Boolean values are stored directly inside a `basic_json` type. @@ -45,6 +45,10 @@ Boolean values are stored directly inside a `basic_json` type. --8<-- "examples/boolean_t.output" ``` +## See also + +- [is_boolean](is_boolean.md) checks whether the JSON value is a boolean + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/cbegin.md b/docs/mkdocs/docs/api/basic_json/cbegin.md index 06504fee6..c0ecebcf3 100644 --- a/docs/mkdocs/docs/api/basic_json/cbegin.md +++ b/docs/mkdocs/docs/api/basic_json/cbegin.md @@ -36,6 +36,13 @@ Constant. --8<-- "examples/cbegin.output" ``` +## See also + +- [begin](begin.md) returns an iterator to the first element +- [cend](cend.md) returns a const iterator to one past the last element +- [crbegin](crbegin.md) returns a const reverse iterator to the last element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md b/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md index 28bd99535..dfeb5d693 100644 --- a/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md +++ b/docs/mkdocs/docs/api/basic_json/cbor_tag_handler_t.md @@ -38,6 +38,12 @@ store --8<-- "examples/cbor_tag_handler_t.output" ``` +## See also + +- [from_cbor](from_cbor.md) deserializes a JSON value from CBOR +- [input_format_t](input_format_t.md) the enumeration of supported input formats +- [CBOR](../../features/binary_formats/cbor.md) - the article on the CBOR format + ## Version history - Added in version 3.9.0. Added value `store` in 3.10.0. diff --git a/docs/mkdocs/docs/api/basic_json/cend.md b/docs/mkdocs/docs/api/basic_json/cend.md index 3f3aa949d..0f944b48c 100644 --- a/docs/mkdocs/docs/api/basic_json/cend.md +++ b/docs/mkdocs/docs/api/basic_json/cend.md @@ -36,6 +36,13 @@ Constant. --8<-- "examples/cend.output" ``` +## See also + +- [end](end.md) returns an iterator to one past the last element +- [cbegin](cbegin.md) returns a const iterator to the first element +- [crend](crend.md) returns a const reverse iterator to one before the first element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/clear.md b/docs/mkdocs/docs/api/basic_json/clear.md index 427a7fc39..57ca31de5 100644 --- a/docs/mkdocs/docs/api/basic_json/clear.md +++ b/docs/mkdocs/docs/api/basic_json/clear.md @@ -52,6 +52,11 @@ All iterators, pointers, and references related to this container are invalidate --8<-- "examples/clear.output" ``` +## See also + +- [erase](erase.md) removes elements from a JSON value +- [empty](empty.md) checks whether the JSON value has no elements + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/contains.md b/docs/mkdocs/docs/api/basic_json/contains.md index 7f865f83c..5ce3e6383 100644 --- a/docs/mkdocs/docs/api/basic_json/contains.md +++ b/docs/mkdocs/docs/api/basic_json/contains.md @@ -63,6 +63,18 @@ Logarithmic in the size of the JSON object. If `#!cpp j.contains(x)` returns `#!c true` for a key or JSON pointer `x`, then it is safe to call `j[x]`. +!!! warning "Deprecation" + + Overload (3) also accepts a [`json_pointer`](../json_pointer/index.md) whose template argument is a `basic_json` + specialization (e.g., `nlohmann::json_pointer`) instead of a string type. This is deprecated since + version 3.11.0 and will be removed in a future major version; use `basic_json::json_pointer` (for `json`, + `nlohmann::json_pointer`) instead. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. + + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example "Example: (1) check with key" diff --git a/docs/mkdocs/docs/api/basic_json/crbegin.md b/docs/mkdocs/docs/api/basic_json/crbegin.md index 95680fb3a..545f86044 100644 --- a/docs/mkdocs/docs/api/basic_json/crbegin.md +++ b/docs/mkdocs/docs/api/basic_json/crbegin.md @@ -36,6 +36,13 @@ Constant. --8<-- "examples/crbegin.output" ``` +## See also + +- [crend](crend.md) returns a const reverse iterator to one before the first element +- [rbegin](rbegin.md) returns a reverse iterator to the last element +- [cbegin](cbegin.md) returns a const iterator to the first element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/crend.md b/docs/mkdocs/docs/api/basic_json/crend.md index 19c581dfe..56cc40c52 100644 --- a/docs/mkdocs/docs/api/basic_json/crend.md +++ b/docs/mkdocs/docs/api/basic_json/crend.md @@ -37,6 +37,13 @@ Constant. --8<-- "examples/crend.output" ``` +## See also + +- [crbegin](crbegin.md) returns a const reverse iterator to the last element +- [rend](rend.md) returns a reverse iterator to one before the first element +- [cend](cend.md) returns a const iterator to one past the last element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md b/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md index 8a237f662..2c3a50217 100644 --- a/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md +++ b/docs/mkdocs/docs/api/basic_json/default_object_comparator_t.md @@ -30,6 +30,11 @@ The actual comparator used depends on [`object_t`](object_t.md) and can be obtai --8<-- "examples/default_object_comparator_t.output" ``` +## See also + +- [object_comparator_t](object_comparator_t.md) the comparator actually used by `object_t` +- [object_t](object_t.md) the type used to store JSON objects + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/basic_json/emplace.md b/docs/mkdocs/docs/api/basic_json/emplace.md index 18286e83f..26044a597 100644 --- a/docs/mkdocs/docs/api/basic_json/emplace.md +++ b/docs/mkdocs/docs/api/basic_json/emplace.md @@ -31,7 +31,8 @@ a `#!cpp bool` denoting whether the insertion took place. ## Exception safety -Strong guarantee: if an exception is thrown, there are no changes to any JSON value. +Strong guarantee: if an exception is thrown, there are no changes to any JSON value. As an exception, a `#!json null` +value is converted to an empty object before the element is added and keeps that type if adding the element throws. ## Exceptions diff --git a/docs/mkdocs/docs/api/basic_json/emplace_back.md b/docs/mkdocs/docs/api/basic_json/emplace_back.md index 516a66e5d..782b61f36 100644 --- a/docs/mkdocs/docs/api/basic_json/emplace_back.md +++ b/docs/mkdocs/docs/api/basic_json/emplace_back.md @@ -28,6 +28,11 @@ iterator is invalidated. reference to the inserted element +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes to any JSON value. As an exception, a `#!json null` +value is converted to an empty array before the element is added and keeps that type if adding the element throws. + ## Exceptions Throws [`type_error.311`](../../home/exceptions.md#jsonexceptiontype_error311) when called on a type other than JSON diff --git a/docs/mkdocs/docs/api/basic_json/empty.md b/docs/mkdocs/docs/api/basic_json/empty.md index 8d566738d..1d393d76e 100644 --- a/docs/mkdocs/docs/api/basic_json/empty.md +++ b/docs/mkdocs/docs/api/basic_json/empty.md @@ -60,6 +60,11 @@ itself is empty which is `#!cpp false` in the case of a string. --8<-- "examples/empty.output" ``` +## See also + +- [size](size.md) returns the number of elements +- [clear](clear.md) clears the content and resets the value to the default value + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/end.md b/docs/mkdocs/docs/api/basic_json/end.md index 179ce9e67..bb735c6df 100644 --- a/docs/mkdocs/docs/api/basic_json/end.md +++ b/docs/mkdocs/docs/api/basic_json/end.md @@ -37,6 +37,13 @@ Constant. --8<-- "examples/end.output" ``` +## See also + +- [begin](begin.md) returns an iterator to the first element +- [cend](cend.md) returns a const iterator to one past the last element +- [rend](rend.md) returns a reverse iterator to one before the first element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/error_handler_t.md b/docs/mkdocs/docs/api/basic_json/error_handler_t.md index f20c33c03..51dc6510f 100644 --- a/docs/mkdocs/docs/api/basic_json/error_handler_t.md +++ b/docs/mkdocs/docs/api/basic_json/error_handler_t.md @@ -37,6 +37,11 @@ ignore --8<-- "examples/error_handler_t.output" ``` +## See also + +- [dump](dump.md) serializes a JSON value, with an `error_handler_t` parameter to configure invalid UTF-8 handling +- [Handling invalid UTF-8](../../features/serialization.md#handling-invalid-utf-8) - the article on handling invalid UTF-8 + ## Version history - Added in version 3.4.0. diff --git a/docs/mkdocs/docs/api/basic_json/flatten.md b/docs/mkdocs/docs/api/basic_json/flatten.md index 7b26a8900..a232a538a 100644 --- a/docs/mkdocs/docs/api/basic_json/flatten.md +++ b/docs/mkdocs/docs/api/basic_json/flatten.md @@ -27,7 +27,7 @@ Empty objects and arrays are flattened to `#!json null` and will not be reconstr ## Examples -??? example +??? example "Example: flatten a JSON object" The following code shows how a JSON object is flattened to an object whose keys consist of JSON pointers. @@ -41,6 +41,21 @@ Empty objects and arrays are flattened to `#!json null` and will not be reconstr --8<-- "examples/flatten.output" ``` +??? example "Example: empty objects and arrays are flattened to `#!json null`" + + The following code shows that an empty object and an empty array are both flattened to `#!json null`, and that + `unflatten()` restores them as `#!json null` rather than as empty containers. + + ```cpp + --8<-- "examples/flatten__empty.cpp" + ``` + + Output: + + ```json + --8<-- "examples/flatten__empty.output" + ``` + ## See also - [unflatten](unflatten.md) the reverse function diff --git a/docs/mkdocs/docs/api/basic_json/from_bson.md b/docs/mkdocs/docs/api/basic_json/from_bson.md index cf022aeb6..9dfd9dc18 100644 --- a/docs/mkdocs/docs/api/basic_json/from_bson.md +++ b/docs/mkdocs/docs/api/basic_json/from_bson.md @@ -123,3 +123,5 @@ Linear in the size of the input. You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/from_cbor.md b/docs/mkdocs/docs/api/basic_json/from_cbor.md index 8c1062da8..791c183bb 100644 --- a/docs/mkdocs/docs/api/basic_json/from_cbor.md +++ b/docs/mkdocs/docs/api/basic_json/from_cbor.md @@ -133,3 +133,5 @@ Linear in the size of the input. You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/from_msgpack.md b/docs/mkdocs/docs/api/basic_json/from_msgpack.md index e41edfe7e..395512acb 100644 --- a/docs/mkdocs/docs/api/basic_json/from_msgpack.md +++ b/docs/mkdocs/docs/api/basic_json/from_msgpack.md @@ -125,3 +125,5 @@ Linear in the size of the input. You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/from_ubjson.md b/docs/mkdocs/docs/api/basic_json/from_ubjson.md index 0d060c750..1ad076588 100644 --- a/docs/mkdocs/docs/api/basic_json/from_ubjson.md +++ b/docs/mkdocs/docs/api/basic_json/from_ubjson.md @@ -124,3 +124,5 @@ Linear in the size of the input. You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/get.md b/docs/mkdocs/docs/api/basic_json/get.md index 8329de919..0dcd3189f 100644 --- a/docs/mkdocs/docs/api/basic_json/get.md +++ b/docs/mkdocs/docs/api/basic_json/get.md @@ -13,16 +13,16 @@ BasicJsonType get() const; // (3) template -PointerType get_ptr(); +PointerType get() noexcept; template -constexpr const PointerType get_ptr() const noexcept; +const PointerType get() const noexcept; // constexpr since C++14 ``` 1. Explicit type conversion between the JSON value and a compatible value which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). The value is converted by - calling the `json_serializer` `from_json()` method. + calling the [`json_serializer`](json_serializer.md) `from_json()` method. The function is equivalent to executing ```cpp @@ -84,6 +84,12 @@ constexpr const PointerType get_ptr() const noexcept; 3. pointer to the internally stored JSON value if the requested pointer type fits to the JSON value; `#!cpp nullptr` otherwise +## Exception safety + +Depends on what `json_serializer` `from_json()` method throws for overloads (1) and (2); the JSON value +itself is never modified, since `get()` is a `#!cpp const` member function. No-throw guarantee for overload (3): this +function never throws exceptions. + ## Exceptions Depends on what `json_serializer` `from_json()` method throws @@ -123,13 +129,13 @@ overload (3). ## Examples -??? example +??? example "Example: (1) explicit conversion to compatible types" The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers, (2) A JSON array can be converted to a standard `std::vector`, (3) A JSON object can be converted to C++ - associative containers such as `std::unordered_map`. + associative containers such as `std::map`. ```cpp --8<-- "examples/get__ValueType_const.cpp" @@ -141,7 +147,21 @@ overload (3). --8<-- "examples/get__ValueType_const.output" ``` -??? example +??? example "Example: (2) explicit conversion to another `basic_json` specialization" + + The example below shows how a `json` value is converted to an `ordered_json` value using `get()`. + + ```cpp + --8<-- "examples/get__BasicJsonType.cpp" + ``` + + Output: + + ```json + --8<-- "examples/get__BasicJsonType.output" + ``` + +??? example "Example: (3) explicit pointer access to the stored value" The example below shows how pointers to internal values of a JSON value can be requested. Note that no type conversions are made and a `#cpp nullptr` is returned if the value and the requested pointer type does not match. diff --git a/docs/mkdocs/docs/api/basic_json/get_allocator.md b/docs/mkdocs/docs/api/basic_json/get_allocator.md index 07a4d8456..46f71dff6 100644 --- a/docs/mkdocs/docs/api/basic_json/get_allocator.md +++ b/docs/mkdocs/docs/api/basic_json/get_allocator.md @@ -10,6 +10,14 @@ Returns the allocator associated with the container. associated allocator +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes to any JSON value. + +## Complexity + +Constant. + ## Examples ??? example @@ -26,6 +34,11 @@ associated allocator --8<-- "examples/get_allocator.output" ``` +## See also + +- [basic_json](index.md#template-parameters) the class template, with `AllocatorType` as one of its template parameters +- [Template Parameter Requirements](../../features/types/template_parameters.md#allocatortype) - the requirements for `AllocatorType` + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/get_to.md b/docs/mkdocs/docs/api/basic_json/get_to.md index c50c077b0..1839e959a 100644 --- a/docs/mkdocs/docs/api/basic_json/get_to.md +++ b/docs/mkdocs/docs/api/basic_json/get_to.md @@ -8,7 +8,7 @@ ValueType& get_to(ValueType& v) const noexcept( ``` Explicit type conversion between the JSON value and a compatible value. The value is filled into the input parameter by -calling the `json_serializer` `from_json()` method. +calling the [`json_serializer`](json_serializer.md) `from_json()` method. The function is equivalent to executing ```cpp @@ -34,6 +34,11 @@ the compiler reports that no matching `get_to` was found. the input parameter, allowing chaining calls +## Exception safety + +Depends on what `json_serializer` `from_json()` method throws; the JSON value itself is never modified, +since `get_to()` is a `#!cpp const` member function. + ## Exceptions Depends on what `json_serializer` `from_json()` method throws @@ -49,7 +54,7 @@ Depends on the `json_serializer::from_json()` implementation. The example below shows several conversions from JSON values to other types. There a few things to note: (1) Floating-point numbers can be converted to integers, (2) A JSON array can be converted to a standard `#!cpp std::vector`, (3) A JSON object can be converted to C++ associative containers such as - `#cpp std::unordered_map`. + `#!cpp std::map`. ```cpp --8<-- "examples/get_to.cpp" diff --git a/docs/mkdocs/docs/api/basic_json/input_format_t.md b/docs/mkdocs/docs/api/basic_json/input_format_t.md index 407b43427..34a80e3f7 100644 --- a/docs/mkdocs/docs/api/basic_json/input_format_t.md +++ b/docs/mkdocs/docs/api/basic_json/input_format_t.md @@ -51,6 +51,11 @@ bon8 --8<-- "examples/sax_parse__binary.output" ``` +## See also + +- [sax_parse](sax_parse.md) generic SAX parse interface, taking an `input_format_t` to select the input format +- [cbor_tag_handler_t](cbor_tag_handler_t.md) configures how CBOR tags are treated while parsing + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/basic_json/insert.md b/docs/mkdocs/docs/api/basic_json/insert.md index fcb1e6e44..848a66315 100644 --- a/docs/mkdocs/docs/api/basic_json/insert.md +++ b/docs/mkdocs/docs/api/basic_json/insert.md @@ -109,11 +109,11 @@ Strong exception safety: if an exception occurs, the original value stays intact 2. Linear in `cnt` plus linear in the distance between `pos` and end of the container. 3. Linear in `#!cpp std::distance(first, last)` plus linear in the distance between `pos` and end of the container. 4. Linear in `ilist.size()` plus linear in the distance between `pos` and end of the container. -5. Logarithmic: `O(N*log(size() + N))`, where `N` is the number of elements to insert. +5. `O(N*log(size() + N))`, where `N` is the number of elements to insert. ## Examples -??? example "Example (1): insert element into array" +??? example "Example: (1) insert element into array" The example shows how `insert()` is used. @@ -127,7 +127,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert.output" ``` -??? example "Example (2): insert copies of element into array" +??? example "Example: (2) insert copies of element into array" The example shows how `insert()` is used. @@ -141,7 +141,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert__count.output" ``` -??? example "Example (3): insert a range of elements into an array" +??? example "Example: (3) insert a range of elements into an array" The example shows how `insert()` is used. @@ -155,7 +155,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert__range.output" ``` -??? example "Example (4): insert elements from an initializer list into an array" +??? example "Example: (4) insert elements from an initializer list into an array" The example shows how `insert()` is used. @@ -169,7 +169,7 @@ Strong exception safety: if an exception occurs, the original value stays intact --8<-- "examples/insert__ilist.output" ``` -??? example "Example (5): insert a range of elements into an object" +??? example "Example: (5) insert a range of elements into an object" The example shows how `insert()` is used. diff --git a/docs/mkdocs/docs/api/basic_json/is_array.md b/docs/mkdocs/docs/api/basic_json/is_array.md index 64468c357..af68bdc0d 100644 --- a/docs/mkdocs/docs/api/basic_json/is_array.md +++ b/docs/mkdocs/docs/api/basic_json/is_array.md @@ -34,6 +34,13 @@ Constant. --8<-- "examples/is_array.output" ``` +## See also + +- [is_object](is_object.md) checks whether the JSON value is an object +- [is_structured](is_structured.md) checks whether the JSON value is structured (array or object) +- [type](type.md) returns the type of the JSON value +- [array_t](array_t.md) the type used to store JSON arrays + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/is_binary.md b/docs/mkdocs/docs/api/basic_json/is_binary.md index 2a42e5edf..ecd853fcd 100644 --- a/docs/mkdocs/docs/api/basic_json/is_binary.md +++ b/docs/mkdocs/docs/api/basic_json/is_binary.md @@ -34,6 +34,12 @@ Constant. --8<-- "examples/is_binary.output" ``` +## See also + +- [is_primitive](is_primitive.md) checks whether the JSON value is primitive +- [binary_t](binary_t.md) the type used to store binary values +- [get_binary](get_binary.md) returns a reference to the stored binary value + ## Version history - Added in version 3.8.0. diff --git a/docs/mkdocs/docs/api/basic_json/is_boolean.md b/docs/mkdocs/docs/api/basic_json/is_boolean.md index dc41d84bd..69e85cbfe 100644 --- a/docs/mkdocs/docs/api/basic_json/is_boolean.md +++ b/docs/mkdocs/docs/api/basic_json/is_boolean.md @@ -34,6 +34,11 @@ Constant. --8<-- "examples/is_boolean.output" ``` +## See also + +- [boolean_t](boolean_t.md) the type used to store JSON booleans +- [is_primitive](is_primitive.md) checks whether the JSON value is primitive + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/is_discarded.md b/docs/mkdocs/docs/api/basic_json/is_discarded.md index 56fae2a49..9ab0ab38a 100644 --- a/docs/mkdocs/docs/api/basic_json/is_discarded.md +++ b/docs/mkdocs/docs/api/basic_json/is_discarded.md @@ -55,7 +55,7 @@ with `allow_exceptions` set to `#!cpp false`: a parse error then yields a discar ## Examples -??? example +??? example "Example: `is_discarded()` for ordinary JSON values" The following code exemplifies `is_discarded()` for all JSON types. @@ -69,6 +69,22 @@ with `allow_exceptions` set to `#!cpp false`: a parse error then yields a discar --8<-- "examples/is_discarded.output" ``` +??? example "Example: discarded values from parsing" + + The following code shows the two situations in which a discarded value can be observed: parsing invalid JSON with + `allow_exceptions` set to `#!cpp false`, and a parser callback that discards the top-level value (which is replaced + by `#!json null` and therefore does *not* remain discarded). + + ```cpp + --8<-- "examples/is_discarded__parse.cpp" + ``` + + Output: + + ```json + --8<-- "examples/is_discarded__parse.output" + ``` + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/is_null.md b/docs/mkdocs/docs/api/basic_json/is_null.md index d080ad32f..e90a6c7ea 100644 --- a/docs/mkdocs/docs/api/basic_json/is_null.md +++ b/docs/mkdocs/docs/api/basic_json/is_null.md @@ -34,6 +34,13 @@ Constant. --8<-- "examples/is_null.output" ``` +## See also + +- [is_array](is_array.md) checks whether the JSON value is an array +- [is_object](is_object.md) checks whether the JSON value is an object +- [type](type.md) returns the type of the JSON value +- [value_t](value_t.md) the enumeration of JSON types + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/is_object.md b/docs/mkdocs/docs/api/basic_json/is_object.md index 04457013b..17776a8bc 100644 --- a/docs/mkdocs/docs/api/basic_json/is_object.md +++ b/docs/mkdocs/docs/api/basic_json/is_object.md @@ -34,6 +34,13 @@ Constant. --8<-- "examples/is_object.output" ``` +## See also + +- [is_array](is_array.md) checks whether the JSON value is an array +- [is_structured](is_structured.md) checks whether the JSON value is structured (array or object) +- [type](type.md) returns the type of the JSON value +- [object_t](object_t.md) the type used to store JSON objects + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/is_string.md b/docs/mkdocs/docs/api/basic_json/is_string.md index b82c92465..d91eaf0a8 100644 --- a/docs/mkdocs/docs/api/basic_json/is_string.md +++ b/docs/mkdocs/docs/api/basic_json/is_string.md @@ -34,6 +34,12 @@ Constant. --8<-- "examples/is_string.output" ``` +## See also + +- [is_primitive](is_primitive.md) checks whether the JSON value is primitive +- [type](type.md) returns the type of the JSON value +- [string_t](string_t.md) the type used to store JSON strings + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/items.md b/docs/mkdocs/docs/api/basic_json/items.md index 3f3d1f2ca..65637001b 100644 --- a/docs/mkdocs/docs/api/basic_json/items.md +++ b/docs/mkdocs/docs/api/basic_json/items.md @@ -114,3 +114,5 @@ When iterating over an array, `key()` will return the index of the element as st You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#miscellaneous-functions) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/json_base_class_t.md b/docs/mkdocs/docs/api/basic_json/json_base_class_t.md index 7add54098..0d1abc9d4 100644 --- a/docs/mkdocs/docs/api/basic_json/json_base_class_t.md +++ b/docs/mkdocs/docs/api/basic_json/json_base_class_t.md @@ -14,12 +14,12 @@ Examples of such functionality might be metadata, additional member functions (e ## Notes -#### Default type +### Default type The default value for `CustomBaseClass` is `void`. In this case, an [empty base class](https://en.cppreference.com/w/cpp/language/ebo) is used and no additional functionality is injected. -#### Limitations +### Limitations The type `CustomBaseClass` has to be a default-constructible, non-`final` class. `basic_json` only supports copy/move construction/assignment if `CustomBaseClass` does so as well. @@ -43,6 +43,10 @@ A `CustomBaseClass` with non-static data members forfeits `basic_json`'s --8<-- "examples/json_base_class_t.output" ``` +## See also + +- [Template Parameter Requirements](../../features/types/template_parameters.md#custombaseclass) - the requirements for `CustomBaseClass` + ## Version history - Added in version 3.12.0. diff --git a/docs/mkdocs/docs/api/basic_json/json_serializer.md b/docs/mkdocs/docs/api/basic_json/json_serializer.md index b92cf3d17..20e9cfd44 100644 --- a/docs/mkdocs/docs/api/basic_json/json_serializer.md +++ b/docs/mkdocs/docs/api/basic_json/json_serializer.md @@ -15,11 +15,11 @@ using json_serializer = JSONSerializer; ## Notes -#### Default type +### Default type The default values for `json_serializer` is [`adl_serializer`](../adl_serializer/index.md). -#### Requirements +### Requirements A custom serializer must provide `#!cpp static void to_json(basic_json&, T)` for every type it serializes, and either `#!cpp static void from_json(const basic_json&, T&)` or `#!cpp static T from_json(const basic_json&)` for every type it @@ -42,6 +42,13 @@ deserializes. See [Template Parameter Requirements](../../features/types/templat --8<-- "examples/from_json__non_default_constructible.output" ``` +## See also + +- [adl_serializer](../adl_serializer/index.md) the default `json_serializer` +- [get](get.md) explicit type conversion using the `json_serializer`'s `from_json()` method +- [get_to](get_to.md) explicit type conversion into a variable using the `json_serializer`'s `from_json()` method +- [Arbitrary Type Conversions](../../features/arbitrary_types.md) - the article on converting between JSON values and arbitrary types + ## Version history - Since version 2.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/max_size.md b/docs/mkdocs/docs/api/basic_json/max_size.md index 4c0c57520..5896a2afd 100644 --- a/docs/mkdocs/docs/api/basic_json/max_size.md +++ b/docs/mkdocs/docs/api/basic_json/max_size.md @@ -54,6 +54,12 @@ string elements the JSON value can store which is `1`. Note the output is platform-dependent. +## See also + +- [size](size.md) returns the number of elements +- [array_t](array_t.md) the type used to store JSON arrays +- [object_t](object_t.md) the type used to store JSON objects + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/merge_patch.md b/docs/mkdocs/docs/api/basic_json/merge_patch.md index 1718c9227..af8759ea4 100644 --- a/docs/mkdocs/docs/api/basic_json/merge_patch.md +++ b/docs/mkdocs/docs/api/basic_json/merge_patch.md @@ -33,6 +33,10 @@ Thereby, `Target` is the current object; that is, the patch is applied to the cu `apply_patch` (in) : the patch to apply +## Exception safety + +Basic guarantee: if an exception is thrown during the operation, the JSON value may be partially modified. + ## Complexity Linear in the lengths of `apply_patch`. diff --git a/docs/mkdocs/docs/api/basic_json/number_float_t.md b/docs/mkdocs/docs/api/basic_json/number_float_t.md index 83c7011c5..8419a392d 100644 --- a/docs/mkdocs/docs/api/basic_json/number_float_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_float_t.md @@ -32,18 +32,18 @@ type to use. ## Notes -#### Default type +### Default type With the default values for `NumberFloatType` (`double`), the default value for `number_float_t` is `#!cpp double`. -#### Default behavior +### Default behavior - The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in floating-point literals will be ignored. Internally, the value will be stored as a decimal number. For instance, the C++ floating-point literal `01.2` will be serialized to `1.2`. During deserialization, leading zeros yield an error. - Not-a-number (NaN) values will be serialized to `null`. -#### Limits +### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) states: > This specification allows implementations to set limits on the range and precision of numbers accepted. Since software @@ -55,7 +55,7 @@ This implementation does exactly follow this approach, as it uses double precisi smaller than `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` will be stored as NaN internally and be serialized to `null`. -#### Storage +### Storage Floating-point number values are stored directly inside a `basic_json` type. @@ -75,6 +75,13 @@ Floating-point number values are stored directly inside a `basic_json` type. --8<-- "examples/number_float_t.output" ``` +## See also + +- [number_integer_t](number_integer_t.md) the type used to store JSON integer numbers +- [number_unsigned_t](number_unsigned_t.md) the type used to store JSON unsigned integer numbers +- [is_number_float](is_number_float.md) checks whether the JSON value is a floating-point number +- [Number Handling](../../features/types/number_handling.md) - the article on number handling + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/number_integer_t.md b/docs/mkdocs/docs/api/basic_json/number_integer_t.md index 9a2ffab7f..e7acf192b 100644 --- a/docs/mkdocs/docs/api/basic_json/number_integer_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_integer_t.md @@ -29,18 +29,18 @@ to use. ## Notes -#### Default type +### Default type With the default values for `NumberIntegerType` (`std::int64_t`), the default value for `number_integer_t` is `#!cpp std::int64_t`. -#### Default behavior +### Default behavior - The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++ integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. -#### Limits +### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the range and precision of numbers. @@ -57,7 +57,7 @@ will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [ As this range is a subrange of the exactly supported range [INT64_MIN, INT64_MAX], this class's integer type is interoperable. -#### Storage +### Storage Integer number values are stored directly inside a `basic_json` type. @@ -77,6 +77,13 @@ Integer number values are stored directly inside a `basic_json` type. --8<-- "examples/number_integer_t.output" ``` +## See also + +- [number_unsigned_t](number_unsigned_t.md) the type used to store JSON unsigned integer numbers +- [number_float_t](number_float_t.md) the type used to store JSON floating-point numbers +- [is_number_integer](is_number_integer.md) checks whether the JSON value is a signed integer number +- [Number Handling](../../features/types/number_handling.md) - the article on number handling + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md b/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md index 674f7711d..c2907ebec 100644 --- a/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md +++ b/docs/mkdocs/docs/api/basic_json/number_unsigned_t.md @@ -30,18 +30,18 @@ the type to use. ## Notes -#### Default type +### Default type With the default values for `NumberUnsignedType` (`std::uint64_t`), the default value for `number_unsigned_t` is `#!cpp std::uint64_t`. -#### Default behavior +### Default behavior - The restrictions about leading zeros are not enforced in C++. Instead, leading zeros in integer literals lead to an interpretation as an octal number. Internally, the value will be stored as a decimal number. For instance, the C++ integer literal `010` will be serialized to `8`. During deserialization, leading zeros yield an error. -#### Limits +### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the range and precision of numbers. @@ -58,7 +58,7 @@ as [`number_integer_t`](number_integer_t.md) or [`number_float_t`](number_float_ As this range is a subrange (when considered in conjunction with the `number_integer_t` type) of the exactly supported range [0, UINT64_MAX], this class's integer type is interoperable. -#### Storage +### Storage Integer number values are stored directly inside a `basic_json` type. @@ -78,6 +78,13 @@ Integer number values are stored directly inside a `basic_json` type. --8<-- "examples/number_unsigned_t.output" ``` +## See also + +- [number_integer_t](number_integer_t.md) the type used to store JSON integer numbers +- [number_float_t](number_float_t.md) the type used to store JSON floating-point numbers +- [is_number_unsigned](is_number_unsigned.md) checks whether the JSON value is an unsigned integer number +- [Number Handling](../../features/types/number_handling.md) - the article on number handling + ## Version history - Added in version 2.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/object_comparator_t.md b/docs/mkdocs/docs/api/basic_json/object_comparator_t.md index bbda0a0e7..7f2982703 100644 --- a/docs/mkdocs/docs/api/basic_json/object_comparator_t.md +++ b/docs/mkdocs/docs/api/basic_json/object_comparator_t.md @@ -25,6 +25,11 @@ and [`default_object_comparator_t`](default_object_comparator_t.md) otherwise. --8<-- "examples/object_comparator_t.output" ``` +## See also + +- [object_t](object_t.md) the type used to store JSON objects +- [default_object_comparator_t](default_object_comparator_t.md) the fallback comparator used when `object_t` has no `key_compare` member type + ## Version history - Added in version 3.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/object_t.md b/docs/mkdocs/docs/api/basic_json/object_t.md index 6ce393a1d..204e5ab28 100644 --- a/docs/mkdocs/docs/api/basic_json/object_t.md +++ b/docs/mkdocs/docs/api/basic_json/object_t.md @@ -33,7 +33,7 @@ To store objects in C++, a type is defined by the template parameters described ## Notes -#### Default type +### Default type With the default values for `ObjectType` (`std::map`), `StringType` (`std::string`), and `AllocatorType` (`std::allocator`), the default value for `object_t` is: @@ -58,7 +58,7 @@ std::map< See [`default_object_comparator_t`](default_object_comparator_t.md) for more information. -#### Behavior +### Behavior The choice of `object_t` influences the behavior of the JSON class. With the default type, objects have the following behavior: @@ -76,7 +76,7 @@ behavior: that they will not be affected by these differences. For instance, `#!json {"b": 1, "a": 2}` and `#!json {"a": 2, "b": 1}` will be treated as equal. -#### Limits +### Limits [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: > An implementation may set limits on the maximum depth of nesting. @@ -85,12 +85,12 @@ In this class, the object's limit of nesting is not explicitly constrained. Howe introduced by the compiler or runtime environment. A theoretical limit can be queried by calling the [`max_size`](max_size.md) function of a JSON object. -#### Storage +### Storage Objects are stored as pointers in a `basic_json` type. That is, for any access to object values, a pointer of type `object_t*` must be dereferenced. -#### Object key order +### Object key order The order name/value pairs are added to the object are *not* preserved by the library. Therefore, iterating an object may return name/value pairs in a different order than they were originally stored. In fact, keys will be traversed in @@ -98,10 +98,10 @@ alphabetical order as `std::map` with `std::less` is used by default. Please not [RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON objects. -#### Cross-`basic_json` conversion requirements +### Cross-`basic_json` conversion requirements When converting an object from one `basic_json` specialization to another via the -[converting constructor](basic_json.md#overload-4), the target `object_t`'s `key_type` must be +[converting constructor](basic_json.md) (overload 4), the target `object_t`'s `key_type` must be directly constructible from the source `basic_json`'s `string_t` type (or more generally, from the source object's key type). If this requirement is not met, the conversion does not fail; instead, the object is silently converted as an array of key-value pairs, which is incorrect. See @@ -123,6 +123,13 @@ the object is silently converted as an array of key-value pairs, which is incorr --8<-- "examples/object_t.output" ``` +## See also + +- [array_t](array_t.md) the type used to store JSON arrays +- [string_t](string_t.md) the type used to store JSON strings +- [object_comparator_t](object_comparator_t.md) the comparator used to order object keys +- [Object Order](../../features/object_order.md) - the article on object key ordering + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/operator+=.md b/docs/mkdocs/docs/api/basic_json/operator+=.md index f296d5c4a..a3dc61b64 100644 --- a/docs/mkdocs/docs/api/basic_json/operator+=.md +++ b/docs/mkdocs/docs/api/basic_json/operator+=.md @@ -48,6 +48,12 @@ invalidates all iterators and all references. `#!cpp *this` +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes to any JSON value. As an exception, a `#!json null` +value is converted to an empty array or object before the element is added and keeps that type if adding the element +throws. + ## Exceptions 1. Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than diff --git a/docs/mkdocs/docs/api/basic_json/operator[].md b/docs/mkdocs/docs/api/basic_json/operator[].md index 3195870e4..350d2bfb0 100644 --- a/docs/mkdocs/docs/api/basic_json/operator[].md +++ b/docs/mkdocs/docs/api/basic_json/operator[].md @@ -133,6 +133,18 @@ Strong exception safety: if an exception occurs, the original value stays intact while `/foo/one/one/one` creates nested objects. This is not specified by the JSON Pointer RFC; it is this library's own, intentional disambiguation rule. See also [JSON Pointer](../../features/json_pointer.md). +!!! warning "Deprecation" + + Overload (4) also accepts a [`json_pointer`](../json_pointer/index.md) whose template argument is a `basic_json` + specialization (e.g., `nlohmann::json_pointer`) instead of a string type. This is deprecated since + version 3.11.0 and will be removed in a future major version; use `basic_json::json_pointer` (for `json`, + `nlohmann::json_pointer`) instead. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. + + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example "Example: (1) access specified array element" diff --git a/docs/mkdocs/docs/api/basic_json/operator_ValueType.md b/docs/mkdocs/docs/api/basic_json/operator_ValueType.md index 231a33df4..48abfb3b5 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_ValueType.md +++ b/docs/mkdocs/docs/api/basic_json/operator_ValueType.md @@ -17,6 +17,11 @@ Implicit type conversion between the JSON value and a compatible value. The call copy of the JSON value, converted to `ValueType` +## Exception safety + +Depends on what `json_serializer` `from_json()` method throws; the JSON value itself is never modified, +since `#!cpp operator ValueType()` is a `#!cpp const` member function that only calls [`get()`](get.md). + ## Exceptions Depends on what `json_serializer` `from_json()` method throws @@ -56,6 +61,8 @@ Linear in the size of the JSON value. [`JSON_USE_IMPLICIT_CONVERSIONS`](../macros/json_use_implicit_conversions.md) to `0` and replace any implicit conversions with calls to [`get`](../basic_json/get.md). + See the [migration guide](../../integration/migration_guide.md#replace-implicit-conversions) for how to update existing code. + ## Examples ??? example @@ -63,7 +70,7 @@ Linear in the size of the JSON value. The example below shows several conversions from JSON values to other types. There are a few things to note: (1) Floating-point numbers can be converted to integers, (2) A JSON array can be converted to a standard `std::vector`, (3) A JSON object can be converted to C++ associative containers such as - `std::unordered_map`. + `std::map`. ```cpp --8<-- "examples/operator__ValueType.cpp" diff --git a/docs/mkdocs/docs/api/basic_json/operator_eq.md b/docs/mkdocs/docs/api/basic_json/operator_eq.md index b575622d1..26eda720f 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_eq.md +++ b/docs/mkdocs/docs/api/basic_json/operator_eq.md @@ -134,7 +134,7 @@ Linear. ## Examples -??? example +??? example "Example: (1) compare JSON values" The example demonstrates comparing several JSON types. @@ -148,7 +148,7 @@ Linear. --8<-- "examples/operator__equal.output" ``` -??? example +??? example "Example: (2) compare JSON values with `#!cpp nullptr`" The example demonstrates comparing several JSON types against the null pointer (JSON `#!json null`). diff --git a/docs/mkdocs/docs/api/basic_json/operator_ge.md b/docs/mkdocs/docs/api/basic_json/operator_ge.md index 9ae6ada86..f7899beab 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_ge.md +++ b/docs/mkdocs/docs/api/basic_json/operator_ge.md @@ -60,6 +60,16 @@ Linear. Since C++20 overload resolution will consider the _rewritten candidate_ generated from [`operator<=>`](operator_spaceship.md). +!!! warning "Deprecation" + + If [`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../macros/json_use_legacy_discarded_value_comparison.md) is + defined to `1`, the library declares a member `#!cpp bool operator>=(const_reference rhs) const noexcept` in + C++20 mode to emulate the legacy comparison of discarded values. This member is deprecated since version 3.11.0, + together with the legacy comparison behavior. + + See the [migration guide](../../integration/migration_guide.md#miscellaneous-functions) for how to update existing + code. + ## Examples ??? example diff --git a/docs/mkdocs/docs/api/basic_json/operator_le.md b/docs/mkdocs/docs/api/basic_json/operator_le.md index 9dfa4e1e0..4334fe35e 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_le.md +++ b/docs/mkdocs/docs/api/basic_json/operator_le.md @@ -61,6 +61,16 @@ Linear. Since C++20 overload resolution will consider the _rewritten candidate_ generated from [`operator<=>`](operator_spaceship.md). +!!! warning "Deprecation" + + If [`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`](../macros/json_use_legacy_discarded_value_comparison.md) is + defined to `1`, the library declares a member `#!cpp bool operator<=(const_reference rhs) const noexcept` in + C++20 mode to emulate the legacy comparison of discarded values. This member is deprecated since version 3.11.0, + together with the legacy comparison behavior. + + See the [migration guide](../../integration/migration_guide.md#miscellaneous-functions) for how to update existing + code. + ## Examples ??? example diff --git a/docs/mkdocs/docs/api/basic_json/operator_ne.md b/docs/mkdocs/docs/api/basic_json/operator_ne.md index 5abb4a5af..a8c6fecc2 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_ne.md +++ b/docs/mkdocs/docs/api/basic_json/operator_ne.md @@ -9,17 +9,9 @@ bool operator!=(const_reference lhs, const ScalarType rhs) noexcept; // (2) template bool operator!=(ScalarType lhs, const const_reference rhs) noexcept; // (2) - -// since C++20 -class basic_json { - bool operator!=(const_reference rhs) const noexcept; // (1) - - template - bool operator!=(ScalarType rhs) const noexcept; // (2) -}; ``` -1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20). +1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)`. - This means the comparison is simply the logical negation of `operator==`, including for special values like `NaN` and `discarded`. 2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON @@ -52,6 +44,11 @@ Linear. ## Notes +!!! note "C++20" + + Since C++20, `basic_json` declares no `operator!=`. The compiler rewrites `#!cpp a != b` as `#!cpp !(a == b)` + using [`operator==`](operator_eq.md), so the result is the same as described above. + !!! note "Comparing `NaN` and `discarded`" Since `operator!=` is defined as `!(a == b)`, the behavior for special values follows that of `operator==`: @@ -61,7 +58,7 @@ Linear. ## Examples -??? example +??? example "Example: (1) compare JSON values" The example demonstrates comparing several JSON types. @@ -75,7 +72,7 @@ Linear. --8<-- "examples/operator__notequal.output" ``` -??? example +??? example "Example: (2) compare JSON values with `#!cpp nullptr`" The example demonstrates comparing several JSON types against the null pointer (JSON `#!json null`). @@ -89,9 +86,15 @@ Linear. --8<-- "examples/operator__notequal__nullptr_t.output" ``` +## See also + +- [operator==](operator_eq.md) comparison: equal +- [operator<=>](operator_spaceship.md) comparison: 3-way (C++20) + ## Version history -1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove - special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`. -2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.13.0 to remove - special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`. +1. Added in version 1.0.0. Added a C++20 member function in version 3.11.0. Changed in version 3.13.0 to remove + special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`. Removed the C++20 + member function in version 3.13.0; since C++20, the compiler rewrites `a != b` using `operator==`. +2. Added in version 1.0.0. Changed in version 3.13.0 to remove special-casing for `NaN` and `discarded` values; + `operator!=` now consistently means `!(a == b)`. Since C++20, the compiler rewrites `a != b` using `operator==`. diff --git a/docs/mkdocs/docs/api/basic_json/operator_value_t.md b/docs/mkdocs/docs/api/basic_json/operator_value_t.md index 0f08f42b0..04915d935 100644 --- a/docs/mkdocs/docs/api/basic_json/operator_value_t.md +++ b/docs/mkdocs/docs/api/basic_json/operator_value_t.md @@ -47,6 +47,11 @@ Constant. --8<-- "examples/operator__value_t.output" ``` +## See also + +- [type](type.md) named member function equivalent to this implicit conversion operator +- [value_t](value_t.md) the enumeration of JSON types + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/parse.md b/docs/mkdocs/docs/api/basic_json/parse.md index 20bb1c708..c26db4745 100644 --- a/docs/mkdocs/docs/api/basic_json/parse.md +++ b/docs/mkdocs/docs/api/basic_json/parse.md @@ -109,7 +109,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by ## Examples -??? example "Parsing from a character array" +??? example "Example: (1) parse from a character array" The example below demonstrates the `parse()` function reading from an array. @@ -123,7 +123,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__array__parser_callback_t.output" ``` -??? example "Parsing from a string" +??? example "Example: (1) parse from a string" The example below demonstrates the `parse()` function with and without callback function. @@ -137,7 +137,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__string__parser_callback_t.output" ``` -??? example "Parsing from an input stream" +??? example "Example: (1) parse from an input stream" The example below demonstrates the `parse()` function with and without callback function. @@ -151,7 +151,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__istream__parser_callback_t.output" ``` -??? example "Parsing from a contiguous container" +??? example "Example: (1) parse from a contiguous container" The example below demonstrates the `parse()` function reading from a contiguous container. @@ -165,7 +165,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__contiguouscontainer__parser_callback_t.output" ``` -??? example "Parsing from a non-null-terminated string" +??? example "Example: (2) parse from a non-null-terminated string" The example below demonstrates the `parse()` function reading from a string that is not null-terminated. @@ -179,7 +179,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__pointers.output" ``` -??? example "Parsing from an iterator pair" +??? example "Example: (2) parse from an iterator pair" The example below demonstrates the `parse()` function reading from an iterator pair. @@ -193,7 +193,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__iterator_pair.output" ``` -??? example "Effect of `allow_exceptions` parameter" +??? example "Example: effect of `allow_exceptions` parameter" The example below demonstrates the effect of the `allow_exceptions` parameter in the `parse()` function. @@ -207,7 +207,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/parse__allow_exceptions.output" ``` -??? example "Effect of `ignore_comments` parameter" +??? example "Example: effect of `ignore_comments` parameter" The example below demonstrates the effect of the `ignore_comments` parameter in the `parse()` function. @@ -221,7 +221,7 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by --8<-- "examples/comments.output" ``` -??? example "Effect of `ignore_trailing_commas` parameter" +??? example "Example: effect of `ignore_trailing_commas` parameter" The example below demonstrates the effect of the `ignore_trailing_commas` parameter in the `parse()` function. @@ -263,3 +263,5 @@ outside of a string, invalid) byte; see the [FAQ entry](../../home/faq.md#nul-by You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated function. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/parse_event_t.md b/docs/mkdocs/docs/api/basic_json/parse_event_t.md index 36cba925f..f8c12eff8 100644 --- a/docs/mkdocs/docs/api/basic_json/parse_event_t.md +++ b/docs/mkdocs/docs/api/basic_json/parse_event_t.md @@ -24,6 +24,21 @@ The parser callback distinguishes the following events: ![Example when certain parse events are triggered](../../images/callback_events.png) +??? example + + The following code parses a small JSON text with a parser callback that reports every event together with its + depth and keeps every value (by always returning `#!cpp true`). + + ```cpp + --8<-- "examples/parse_event_t.cpp" + ``` + + Output: + + ```json + --8<-- "examples/parse_event_t.output" + ``` + ## See also - [parser_callback_t](parser_callback_t.md) callback function type for the parser diff --git a/docs/mkdocs/docs/api/basic_json/parser_callback_t.md b/docs/mkdocs/docs/api/basic_json/parser_callback_t.md index da23e9bc2..456542ba7 100644 --- a/docs/mkdocs/docs/api/basic_json/parser_callback_t.md +++ b/docs/mkdocs/docs/api/basic_json/parser_callback_t.md @@ -60,7 +60,7 @@ the latter case, it is skipped completely, or replaced by `null` if it is the to ## Examples -??? example +??? example "Example: skip an object key while parsing" The example below demonstrates the `parse()` function with and without callback function. @@ -75,7 +75,7 @@ the latter case, it is skipped completely, or replaced by `null` if it is the to --8<-- "examples/parse__string__parser_callback_t.output" ``` -??? example +??? example "Example: how discarded values are removed" The example below shows where discarded values are removed. The array and the number are discarded in different ways, but in each case the parse result contains neither the value nor its key. diff --git a/docs/mkdocs/docs/api/basic_json/patch.md b/docs/mkdocs/docs/api/basic_json/patch.md index fa25b2699..ab0232691 100644 --- a/docs/mkdocs/docs/api/basic_json/patch.md +++ b/docs/mkdocs/docs/api/basic_json/patch.md @@ -53,7 +53,7 @@ is thrown. In any case, the original value is not changed: the patch is applied ## Examples -??? example +??? example "Example: apply a JSON patch" The following code shows how a JSON patch is applied to a value. @@ -67,6 +67,21 @@ is thrown. In any case, the original value is not changed: the patch is applied --8<-- "examples/patch.output" ``` +??? example "Example: out_of_range.414 exception" + + The following code shows how a "move" operation whose "from" location is a proper prefix of its "path" location is + rejected, and how the original document is left unchanged because the patch is applied to a copy. + + ```cpp + --8<-- "examples/patch__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/patch__exception.output" + ``` + ## See also - [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) diff --git a/docs/mkdocs/docs/api/basic_json/patch_inplace.md b/docs/mkdocs/docs/api/basic_json/patch_inplace.md index 7ae85aaaa..0b6605314 100644 --- a/docs/mkdocs/docs/api/basic_json/patch_inplace.md +++ b/docs/mkdocs/docs/api/basic_json/patch_inplace.md @@ -50,7 +50,7 @@ function throws an exception. ## Examples -??? example +??? example "Example: apply a JSON patch in place" The following code shows how a JSON patch is applied to a value. @@ -64,6 +64,22 @@ function throws an exception. --8<-- "examples/patch_inplace.output" ``` +??? example "Example: out_of_range.403 exception with a partially applied patch" + + The following code shows a patch whose first operation succeeds and whose second operation fails. Because + `patch_inplace` applies each operation directly to the value, the first operation's effect is still visible after + the exception is caught, unlike [`patch`](patch.md). + + ```cpp + --8<-- "examples/patch_inplace__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/patch_inplace__exception.output" + ``` + ## See also - [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) diff --git a/docs/mkdocs/docs/api/basic_json/push_back.md b/docs/mkdocs/docs/api/basic_json/push_back.md index 9d518e79e..386a589a3 100644 --- a/docs/mkdocs/docs/api/basic_json/push_back.md +++ b/docs/mkdocs/docs/api/basic_json/push_back.md @@ -44,6 +44,12 @@ invalidates all iterators and all references. `init` (in) : an initializer list +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes to any JSON value. As an exception, a `#!json null` +value is converted to an empty array or object before the element is added and keeps that type if adding the element +throws. + ## Exceptions 1. Throws [`type_error.308`](../../home/exceptions.md#jsonexceptiontype_error308) when called on a type other than diff --git a/docs/mkdocs/docs/api/basic_json/rbegin.md b/docs/mkdocs/docs/api/basic_json/rbegin.md index 5fbbe7d3b..544b8a643 100644 --- a/docs/mkdocs/docs/api/basic_json/rbegin.md +++ b/docs/mkdocs/docs/api/basic_json/rbegin.md @@ -37,6 +37,13 @@ Constant. --8<-- "examples/rbegin.output" ``` +## See also + +- [rend](rend.md) returns a reverse iterator to one before the first element +- [crbegin](crbegin.md) returns a const reverse iterator to the last element +- [begin](begin.md) returns an iterator to the first element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/rend.md b/docs/mkdocs/docs/api/basic_json/rend.md index 8eb1a6e55..12f68e787 100644 --- a/docs/mkdocs/docs/api/basic_json/rend.md +++ b/docs/mkdocs/docs/api/basic_json/rend.md @@ -38,6 +38,13 @@ Constant. --8<-- "examples/rend.output" ``` +## See also + +- [rbegin](rbegin.md) returns a reverse iterator to the last element +- [crend](crend.md) returns a const reverse iterator to one before the first element +- [end](end.md) returns an iterator to one past the last element +- [Iterators](../../features/iterators.md) - the article on iterators + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/sax_parse.md b/docs/mkdocs/docs/api/basic_json/sax_parse.md index d6ce688a7..0d4b8da8a 100644 --- a/docs/mkdocs/docs/api/basic_json/sax_parse.md +++ b/docs/mkdocs/docs/api/basic_json/sax_parse.md @@ -147,3 +147,5 @@ A UTF-8 byte order mark is silently ignored. Overload (2) replaces calls to `sax_parse` with a pair of iterators as their first parameter which has been deprecated in version 3.8.0. This overload will be removed in version 4.0.0. Please replace all calls like `#!cpp sax_parse({ptr, ptr+len});` with `#!cpp sax_parse(ptr, ptr+len);`. + + See the [migration guide](../../integration/migration_guide.md#parsing) for how to update existing code. diff --git a/docs/mkdocs/docs/api/basic_json/size.md b/docs/mkdocs/docs/api/basic_json/size.md index 4ff582db2..c3d9156ba 100644 --- a/docs/mkdocs/docs/api/basic_json/size.md +++ b/docs/mkdocs/docs/api/basic_json/size.md @@ -51,6 +51,11 @@ JSON value which is `1` in the case of a string. --8<-- "examples/size.output" ``` +## See also + +- [empty](empty.md) checks whether the JSON value has no elements +- [max_size](max_size.md) returns the maximum possible number of elements + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/std_hash.md b/docs/mkdocs/docs/api/basic_json/std_hash.md index b9de74f8c..aaa49ed68 100644 --- a/docs/mkdocs/docs/api/basic_json/std_hash.md +++ b/docs/mkdocs/docs/api/basic_json/std_hash.md @@ -28,6 +28,10 @@ type of the JSON value is taken into account to have different hash values for ` Note the output is platform-dependent. +## See also + +- [operator==](operator_eq.md) compares two JSON values for equality, consistent with equal hash values + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/string_t.md b/docs/mkdocs/docs/api/basic_json/string_t.md index e8be0fe0e..13177cef8 100644 --- a/docs/mkdocs/docs/api/basic_json/string_t.md +++ b/docs/mkdocs/docs/api/basic_json/string_t.md @@ -30,16 +30,16 @@ JSON class into byte-sized characters during deserialization. ## Notes -#### Default type +### Default type With the default values for `StringType` (`std::string`), the default value for `string_t` is `#!cpp std::string`. -#### Encoding +### Encoding Strings are stored in UTF-8 encoding. Therefore, functions like `std::string::size()` or `std::string::length()` return the number of bytes in the string rather than the number of characters or glyphs. -#### String comparison +### String comparison [RFC 8259](https://tools.ietf.org/html/rfc8259) states: > Software implementations are typically required to test names of object members for equality. Implementations that @@ -50,15 +50,15 @@ the number of bytes in the string rather than the number of characters or glyphs This implementation is interoperable as it does compare strings code unit by code unit. -#### Storage +### Storage String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type `string_t*` must be dereferenced. -#### Cross-`basic_json` conversion requirements +### Cross-`basic_json` conversion requirements When converting a string value from one `basic_json` specialization to another via the -[converting constructor](basic_json.md#overload-4), the target `string_t` must be directly +[converting constructor](basic_json.md) (overload 4), the target `string_t` must be directly constructible from the source `basic_json`'s `string_t` type. If this requirement is not met, the conversion does not fail; instead, the string is silently converted as an array of character codes, which is incorrect. See [issue #3425](https://github.com/nlohmann/json/issues/3425) for details @@ -80,6 +80,12 @@ and an example. --8<-- "examples/string_t.output" ``` +## See also + +- [object_t](object_t.md) the type used to store JSON objects (and their keys, which are also `string_t`) +- [binary_t](binary_t.md) the type used to store binary values +- [get_ptr](get_ptr.md) returns a pointer to the stored string value + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/swap.md b/docs/mkdocs/docs/api/basic_json/swap.md index aa5aa6c4c..8a5900b98 100644 --- a/docs/mkdocs/docs/api/basic_json/swap.md +++ b/docs/mkdocs/docs/api/basic_json/swap.md @@ -65,6 +65,16 @@ void swap(typename binary_t::container_type& other); `right` (in, out) : value to exchange the contents with +## Exception safety + +1. No-throw guarantee: this function never throws exceptions. +2. No-throw guarantee: this function never throws exceptions. +3. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. +4. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. +5. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. +6. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. +7. Strong guarantee: if an exception is thrown, there are no changes to any JSON value. + ## Exceptions 1. No-throw guarantee: this function never throws exceptions. @@ -86,7 +96,7 @@ Constant. ## Examples -??? example "Example: Swap JSON value (1, 2)" +??? example "Example: (1, 2) swap JSON values" The example below shows how JSON values can be swapped with `swap()`. @@ -100,7 +110,7 @@ Constant. --8<-- "examples/swap__reference.output" ``` -??? example "Example: Swap array (3)" +??? example "Example: (3) swap array" The example below shows how arrays can be swapped with `swap()`. @@ -114,7 +124,7 @@ Constant. --8<-- "examples/swap__array_t.output" ``` -??? example "Example: Swap object (4)" +??? example "Example: (4) swap object" The example below shows how objects can be swapped with `swap()`. @@ -128,7 +138,7 @@ Constant. --8<-- "examples/swap__object_t.output" ``` -??? example "Example: Swap string (5)" +??? example "Example: (5) swap string" The example below shows how strings can be swapped with `swap()`. @@ -142,7 +152,7 @@ Constant. --8<-- "examples/swap__string_t.output" ``` -??? example "Example: Swap binary (6)" +??? example "Example: (6) swap binary" The example below shows how binary values can be swapped with `swap()`. diff --git a/docs/mkdocs/docs/api/basic_json/to_bjdata.md b/docs/mkdocs/docs/api/basic_json/to_bjdata.md index b066e6852..44cc399e1 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bjdata.md +++ b/docs/mkdocs/docs/api/basic_json/to_bjdata.md @@ -55,7 +55,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions - Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size` - is false. + is false, and `j` contains a non-empty array, object, or binary value. ## Complexity @@ -63,7 +63,7 @@ Linear in the size of the JSON value `j`. ## Examples -??? example +??? example "Example: serialize a JSON value to BJData" The example shows the serialization of a JSON value to a byte vector in BJData format. @@ -77,6 +77,21 @@ Linear in the size of the JSON value `j`. --8<-- "examples/to_bjdata.output" ``` +??? example "Example: other_error.502 exception" + + The example shows how requesting type annotations (`use_type`) without size annotations (`use_size`) throws an + exception, because type-optimized containers can only be read back with a preceding size. + + ```cpp + --8<-- "examples/to_bjdata__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/to_bjdata__exception.output" + ``` + ## See also - [from_bjdata](from_bjdata.md) create a JSON value from an input in BJData format diff --git a/docs/mkdocs/docs/api/basic_json/to_bon8.md b/docs/mkdocs/docs/api/basic_json/to_bon8.md index 26d552e8a..2d58b2660 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bon8.md +++ b/docs/mkdocs/docs/api/basic_json/to_bon8.md @@ -48,7 +48,7 @@ Linear in the size of the JSON value `j`. ## Examples -??? example +??? example "Example: serialize a JSON value to BON8" The example shows the serialization of a JSON value to a byte vector in BON8 format. @@ -62,6 +62,21 @@ Linear in the size of the JSON value `j`. --8<-- "examples/to_bon8.output" ``` +??? example "Example: type_error.316 exception" + + The example shows how serializing a string that is not valid UTF-8 throws an exception, because BON8 stores strings + as UTF-8. + + ```cpp + --8<-- "examples/to_bon8__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/to_bon8__exception.output" + ``` + ## See also - [from_bon8](from_bon8.md) create a JSON value from an input in BON8 format diff --git a/docs/mkdocs/docs/api/basic_json/to_bson.md b/docs/mkdocs/docs/api/basic_json/to_bson.md index fb02c51e1..370afa654 100644 --- a/docs/mkdocs/docs/api/basic_json/to_bson.md +++ b/docs/mkdocs/docs/api/basic_json/to_bson.md @@ -51,7 +51,7 @@ pass before anything is written. ## Examples -??? example +??? example "Example: serialize a JSON value to BSON" The example shows the serialization of a JSON value to a byte vector in BSON format. @@ -65,6 +65,21 @@ pass before anything is written. --8<-- "examples/to_bson.output" ``` +??? example "Example: out_of_range.409 exception" + + The example shows how serializing a JSON object whose key contains a null byte (U+0000) throws an exception, because + BSON keys are null-terminated C strings and cannot contain U+0000 themselves. + + ```cpp + --8<-- "examples/to_bson__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/to_bson__exception.output" + ``` + ## See also - [from_bson](from_bson.md) create a JSON value from an input in BSON format diff --git a/docs/mkdocs/docs/api/basic_json/to_msgpack.md b/docs/mkdocs/docs/api/basic_json/to_msgpack.md index 007fb1914..60fc226f4 100644 --- a/docs/mkdocs/docs/api/basic_json/to_msgpack.md +++ b/docs/mkdocs/docs/api/basic_json/to_msgpack.md @@ -49,7 +49,7 @@ Linear in the size of the JSON value `j`. ## Examples -??? example +??? example "Example: serialize a JSON value to MessagePack" The example shows the serialization of a JSON value to a byte vector in MessagePack format. @@ -63,6 +63,21 @@ Linear in the size of the JSON value `j`. --8<-- "examples/to_msgpack.output" ``` +??? example "Example: out_of_range.415 exception" + + The example shows how serializing a binary value whose subtype exceeds 255 throws an exception, because the + MessagePack ext type stores the subtype in a single byte. + + ```cpp + --8<-- "examples/to_msgpack__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/to_msgpack__exception.output" + ``` + ## See also - [from_msgpack](from_msgpack.md) create a JSON value from an input in MessagePack format diff --git a/docs/mkdocs/docs/api/basic_json/to_ubjson.md b/docs/mkdocs/docs/api/basic_json/to_ubjson.md index 6437ba3e5..1b7f7767e 100644 --- a/docs/mkdocs/docs/api/basic_json/to_ubjson.md +++ b/docs/mkdocs/docs/api/basic_json/to_ubjson.md @@ -48,7 +48,7 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va ## Exceptions - Throws [`other_error.502`](../../home/exceptions.md#jsonexceptionother_error502) if `use_type` is true and `use_size` - is false. + is false, and `j` contains a non-empty array, object, or binary value. ## Complexity @@ -56,7 +56,7 @@ Linear in the size of the JSON value `j`. ## Examples -??? example +??? example "Example: serialize a JSON value to UBJSON" The example shows the serialization of a JSON value to a byte vector in UBJSON format. @@ -70,6 +70,21 @@ Linear in the size of the JSON value `j`. --8<-- "examples/to_ubjson.output" ``` +??? example "Example: other_error.502 exception" + + The example shows how requesting type annotations (`use_type`) without size annotations (`use_size`) throws an + exception, because type-optimized containers can only be read back with a preceding size. + + ```cpp + --8<-- "examples/to_ubjson__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/to_ubjson__exception.output" + ``` + ## See also - [from_ubjson](from_ubjson.md) create a JSON value from an input in UBJSON format diff --git a/docs/mkdocs/docs/api/basic_json/type.md b/docs/mkdocs/docs/api/basic_json/type.md index deedd6b69..381e489d2 100644 --- a/docs/mkdocs/docs/api/basic_json/type.md +++ b/docs/mkdocs/docs/api/basic_json/type.md @@ -47,6 +47,12 @@ Constant. --8<-- "examples/type.output" ``` +## See also + +- [operator value_t](operator_value_t.md) implicit conversion operator equivalent to this named member function +- [type_name](type_name.md) returns the type as a string, for use in error messages +- [value_t](value_t.md) the enumeration of JSON types + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/type_name.md b/docs/mkdocs/docs/api/basic_json/type_name.md index 2022b8897..0df2de752 100644 --- a/docs/mkdocs/docs/api/basic_json/type_name.md +++ b/docs/mkdocs/docs/api/basic_json/type_name.md @@ -52,6 +52,11 @@ Constant. --8<-- "examples/type_name.output" ``` +## See also + +- [type](type.md) returns the type of the JSON value +- [value_t](value_t.md) the enumeration of JSON types + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/update.md b/docs/mkdocs/docs/api/basic_json/update.md index b34140dbc..253a78120 100644 --- a/docs/mkdocs/docs/api/basic_json/update.md +++ b/docs/mkdocs/docs/api/basic_json/update.md @@ -61,7 +61,7 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value ## Examples -??? example +??? example "Example: (1) update with another object" The example shows how `update()` is used. @@ -75,7 +75,7 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value --8<-- "examples/update.output" ``` -??? example +??? example "Example: (2) update with an iterator range" The example shows how `update()` is used. @@ -89,7 +89,7 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value --8<-- "examples/update__range.output" ``` -??? example +??? example "Example: (1) merge user settings into default settings" One common use case for this function is the handling of user settings. Assume your application can be configured in some aspects: diff --git a/docs/mkdocs/docs/api/basic_json/value.md b/docs/mkdocs/docs/api/basic_json/value.md index 2e9b85a2b..9a986b534 100644 --- a/docs/mkdocs/docs/api/basic_json/value.md +++ b/docs/mkdocs/docs/api/basic_json/value.md @@ -133,6 +133,18 @@ changes to any JSON value. --8<-- "examples/value__return_type.output" ``` +!!! warning "Deprecation" + + Overload (3) also accepts a [`json_pointer`](../json_pointer/index.md) whose template argument is a `basic_json` + specialization (e.g., `nlohmann::json_pointer`) instead of a string type. This is deprecated since + version 3.11.0 and will be removed in a future major version; use `basic_json::json_pointer` (for `json`, + `nlohmann::json_pointer`) instead. + + You should be warned by your compiler with a `-Wdeprecated-declarations` warning if you are using a deprecated + function. + + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example "Example: (1) access specified object element with default value" @@ -177,6 +189,21 @@ changes to any JSON value. --8<-- "examples/value__json_ptr.output" ``` +??? example "Example: (1) type_error.302 and type_error.306 exceptions" + + The example below shows how `value()` throws `type_error.302` when the default value's type does not match the type + of the stored value, and `type_error.306` when `value()` is called on a JSON value that is not an object. + + ```cpp + --8<-- "examples/value__exception.cpp" + ``` + + Output: + + ```json + --8<-- "examples/value__exception.output" + ``` + ## See also - see [`at`](at.md) for access by reference with range checking diff --git a/docs/mkdocs/docs/api/basic_json/value_t.md b/docs/mkdocs/docs/api/basic_json/value_t.md index 1505e02d0..0d63bfdac 100644 --- a/docs/mkdocs/docs/api/basic_json/value_t.md +++ b/docs/mkdocs/docs/api/basic_json/value_t.md @@ -38,6 +38,16 @@ functions [`is_null`](is_null.md), [`is_object`](is_object.md), [`is_array`](is_ `discarded` is unordered. + ```mermaid + flowchart LR + A[null] --> B[boolean] + B --> C["number_integer / number_unsigned / number_float"] + C --> D[object] + D --> E[array] + E --> F[string] + F --> G[binary] + ``` + !!! note "Types of numbers" There are three enumerators for numbers (`number_integer`, `number_unsigned`, and `number_float`) to distinguish @@ -74,6 +84,14 @@ functions [`is_null`](is_null.md), [`is_object`](is_object.md), [`is_array`](is_ --8<-- "examples/type.output" ``` +## See also + +- [type](type.md) return the type of the JSON value +- [type_name](type_name.md) return the type as string +- [operator value_t](operator_value_t.md) return the type of the JSON value +- [is_primitive](is_primitive.md) return whether the type is primitive +- [is_structured](is_structured.md) return whether the type is structured + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/basic_json/~basic_json.md b/docs/mkdocs/docs/api/basic_json/~basic_json.md index 64e944006..e5b957d51 100644 --- a/docs/mkdocs/docs/api/basic_json/~basic_json.md +++ b/docs/mkdocs/docs/api/basic_json/~basic_json.md @@ -16,6 +16,11 @@ Linear. +## See also + +- [basic_json](basic_json.md) constructs a JSON value +- [clear](clear.md) clears the content of a JSON value without destroying it + ## Version history - Added in version 1.0.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md index c8e47cfa3..23d5c9beb 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/byte_container_with_subtype.md @@ -41,6 +41,14 @@ byte_container_with_subtype(container_type&& container, subtype_type subtype); --8<-- "examples/byte_container_with_subtype__byte_container_with_subtype.output" ``` +## See also + +- [set_subtype](set_subtype.md) sets the binary subtype +- [subtype](subtype.md) return the binary subtype +- [has_subtype](has_subtype.md) return whether the value has a subtype +- [binary](../basic_json/binary.md) create a binary JSON value +- [Binary Values](../../features/binary_values.md) - the article on binary values + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md index f4bb891ee..7fd8fe9a4 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/clear_subtype.md @@ -31,6 +31,12 @@ Constant. --8<-- "examples/byte_container_with_subtype__clear_subtype.output" ``` +## See also + +- [set_subtype](set_subtype.md) sets the binary subtype +- [has_subtype](has_subtype.md) return whether the value has a subtype +- [subtype](subtype.md) return the binary subtype + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md index e06286e29..98596dab0 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/has_subtype.md @@ -34,6 +34,12 @@ Constant. --8<-- "examples/byte_container_with_subtype__has_subtype.output" ``` +## See also + +- [set_subtype](set_subtype.md) sets the binary subtype +- [clear_subtype](clear_subtype.md) clears the binary subtype +- [subtype](subtype.md) return the binary subtype + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/index.md b/docs/mkdocs/docs/api/byte_container_with_subtype/index.md index a9aafc1d2..cb5a3781d 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/index.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/index.md @@ -22,8 +22,8 @@ specific naming scheme in order to override the binary type. ## Member functions - [(constructor)](byte_container_with_subtype.md) -- **operator==** - comparison: equal -- **operator!=** - comparison: not equal +- [**operator==**](operator_eq.md) - comparison: equal +- [**operator!=**](operator_ne.md) - comparison: not equal - [**set_subtype**](set_subtype.md) - sets the binary subtype - [**subtype**](subtype.md) - return the binary subtype - [**has_subtype**](has_subtype.md) - return whether the value has a subtype diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/operator_eq.md b/docs/mkdocs/docs/api/byte_container_with_subtype/operator_eq.md new file mode 100644 index 000000000..0676ee5e7 --- /dev/null +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/operator_eq.md @@ -0,0 +1,48 @@ +# nlohmann::byte_container_with_subtype::operator== + +```cpp +bool operator==(const byte_container_with_subtype& rhs) const; +``` + +Compares two byte containers for equality by comparing (1) the underlying binary data (the `BinaryType` base, compared +with `BinaryType`'s own `operator==`) and (2) the subtype information -- both containers must either have no subtype, +or have a subtype and the same subtype value. + +## Parameters + +`rhs` (in) +: byte container to compare `*this` with + +## Return value + +whether `*this` and `rhs` are equal + +## Complexity + +Linear in the size of the compared containers. + +## Examples + +??? example + + The example below demonstrates comparing byte containers with and without subtypes. + + ```cpp + --8<-- "examples/byte_container_with_subtype__operator__equal.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__operator__equal.output" + ``` + +## See also + +- [operator!=](operator_ne.md) comparison: not equal +- [has_subtype](has_subtype.md) return whether the value has a subtype +- [subtype](subtype.md) return the binary subtype + +## Version history + +- Added in version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/operator_ne.md b/docs/mkdocs/docs/api/byte_container_with_subtype/operator_ne.md new file mode 100644 index 000000000..5adb5cd39 --- /dev/null +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/operator_ne.md @@ -0,0 +1,47 @@ +# nlohmann::byte_container_with_subtype::operator!= + +```cpp +bool operator!=(const byte_container_with_subtype& rhs) const; +``` + +Compares two byte containers for inequality. Returns `#!cpp !(rhs == *this)`; see [`operator==`](operator_eq.md) for +the equality semantics. + +## Parameters + +`rhs` (in) +: byte container to compare `*this` with + +## Return value + +whether `*this` and `rhs` are not equal + +## Complexity + +Linear in the size of the compared containers. + +## Examples + +??? example + + The example below demonstrates comparing byte containers with and without subtypes. + + ```cpp + --8<-- "examples/byte_container_with_subtype__operator__notequal.cpp" + ``` + + Output: + + ```json + --8<-- "examples/byte_container_with_subtype__operator__notequal.output" + ``` + +## See also + +- [operator==](operator_eq.md) comparison: equal +- [has_subtype](has_subtype.md) return whether the value has a subtype +- [subtype](subtype.md) return the binary subtype + +## Version history + +- Added in version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md index cf21732b8..6cd319e1d 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/set_subtype.md @@ -36,6 +36,12 @@ Constant. --8<-- "examples/byte_container_with_subtype__set_subtype.output" ``` +## See also + +- [subtype](subtype.md) return the binary subtype +- [has_subtype](has_subtype.md) return whether the value has a subtype +- [clear_subtype](clear_subtype.md) clears the binary subtype + ## Version history Since version 3.8.0. diff --git a/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md b/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md index 389241a79..0f00cc803 100644 --- a/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md +++ b/docs/mkdocs/docs/api/byte_container_with_subtype/subtype.md @@ -36,6 +36,12 @@ Constant. --8<-- "examples/byte_container_with_subtype__subtype.output" ``` +## See also + +- [set_subtype](set_subtype.md) sets the binary subtype +- [has_subtype](has_subtype.md) return whether the value has a subtype +- [clear_subtype](clear_subtype.md) clears the binary subtype + ## Version history - Added in version 3.8.0 diff --git a/docs/mkdocs/docs/api/json.md b/docs/mkdocs/docs/api/json.md index 36edcc2c1..55504ef9a 100644 --- a/docs/mkdocs/docs/api/json.md +++ b/docs/mkdocs/docs/api/json.md @@ -23,6 +23,11 @@ types. --8<-- "examples/README.output" ``` +## See also + +- [basic_json](basic_json/index.md) - the underlying class template +- [ordered_json](ordered_json.md) - specialization that preserves the insertion order of object keys + ## Version history Since version 1.0.0. diff --git a/docs/mkdocs/docs/api/json_pointer/back.md b/docs/mkdocs/docs/api/json_pointer/back.md index 7b798e368..b8f0432af 100644 --- a/docs/mkdocs/docs/api/json_pointer/back.md +++ b/docs/mkdocs/docs/api/json_pointer/back.md @@ -10,6 +10,10 @@ Return the last reference token. Last reference token. +## Exception safety + +Strong exception safety: if an exception occurs, the original value stays intact. + ## Exceptions Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent. @@ -34,6 +38,13 @@ Constant. --8<-- "examples/json_pointer__back.output" ``` +## See also + +- [front](front.md) return first reference token +- [pop_back](pop_back.md) remove the last reference token +- [push_back](push_back.md) append an unescaped token at the end of the pointer +- [parent_pointer](parent_pointer.md) returns the parent of this JSON pointer + ## Version history - Added in version 3.6.0. diff --git a/docs/mkdocs/docs/api/json_pointer/empty.md b/docs/mkdocs/docs/api/json_pointer/empty.md index 96328bd23..6c8fd542e 100644 --- a/docs/mkdocs/docs/api/json_pointer/empty.md +++ b/docs/mkdocs/docs/api/json_pointer/empty.md @@ -34,6 +34,12 @@ Constant. --8<-- "examples/json_pointer__empty.output" ``` +## See also + +- [front](front.md) return first reference token +- [back](back.md) return last reference token +- [to_string](to_string.md) return a string representation of the JSON pointer + ## Version history Added in version 3.6.0. diff --git a/docs/mkdocs/docs/api/json_pointer/front.md b/docs/mkdocs/docs/api/json_pointer/front.md index afc6f5ca7..247abd188 100644 --- a/docs/mkdocs/docs/api/json_pointer/front.md +++ b/docs/mkdocs/docs/api/json_pointer/front.md @@ -10,6 +10,10 @@ Return the first reference token. First reference token. +## Exception safety + +Strong exception safety: if an exception occurs, the original value stays intact. + ## Exceptions Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent. @@ -34,6 +38,12 @@ Constant. --8<-- "examples/json_pointer__front.output" ``` +## See also + +- [back](back.md) return last reference token +- [pop_front](pop_front.md) remove the first reference token +- [push_front](push_front.md) append an unescaped token at the start of the pointer + ## Version history - Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/json_pointer/index.md b/docs/mkdocs/docs/api/json_pointer/index.md index b1f895375..c64543c94 100644 --- a/docs/mkdocs/docs/api/json_pointer/index.md +++ b/docs/mkdocs/docs/api/json_pointer/index.md @@ -20,6 +20,24 @@ are the base for JSON patches. in which case `string_t` will be deduced as [`basic_json::string_t`](../basic_json/string_t.md). This feature is deprecated and may be removed in a future major version. + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + +A JSON pointer is internally a sequence of reference tokens. [`front`](front.md), [`pop_front`](pop_front.md), and +[`push_front`](push_front.md) act on the first reference token, whereas [`back`](back.md), [`pop_back`](pop_back.md), +and [`push_back`](push_back.md) act on the last one. [`parent_pointer`](parent_pointer.md) returns a new JSON pointer +with the last reference token removed (like a non-mutating [`pop_back`](pop_back.md)): + +```mermaid +flowchart LR + A["a"] --> B["b"] --> C["c"] + + front["front() / pop_front() / push_front()"] -.-> A + back["back() / pop_back() / push_back()"] -.-> C + parent["parent_pointer() returns /a/b"] -.-> B +``` + +The diagram shows the reference tokens of the JSON pointer `/a/b/c`. + ## Member types - [**string_t**](string_t.md) - the string type used for the reference tokens @@ -28,9 +46,10 @@ are the base for JSON patches. - [(constructor)](json_pointer.md) - [**to_string**](to_string.md) - return a string representation of the JSON pointer -- [**operator string_t**](operator_string_t.md) - return a string representation of the JSON pointer +- [**operator string_t**](operator_string_t.md) - return a string representation of the JSON pointer (deprecated) - [**operator==**](operator_eq.md) - compare: equal - [**operator!=**](operator_ne.md) - compare: not equal +- [**operator<=>**](operator_spaceship.md) - compare: 3-way (C++20) - [**operator/=**](operator_slasheq.md) - append to the end of the JSON pointer - [**operator/**](operator_slash.md) - create JSON Pointer by appending - [**parent_pointer**](parent_pointer.md) - returns the parent of this JSON pointer @@ -45,6 +64,7 @@ are the base for JSON patches. ## Literals - [**operator""_json_pointer**](../operator_literal_json_pointer.md) - user-defined string literal for JSON pointers + ## See also - [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901) diff --git a/docs/mkdocs/docs/api/json_pointer/json_pointer.md b/docs/mkdocs/docs/api/json_pointer/json_pointer.md index 5e7057fc9..0fce6f43c 100644 --- a/docs/mkdocs/docs/api/json_pointer/json_pointer.md +++ b/docs/mkdocs/docs/api/json_pointer/json_pointer.md @@ -12,6 +12,10 @@ Create a JSON pointer according to the syntax described in `s` (in) : string representing the JSON pointer; if omitted, the empty string is assumed which references the whole JSON value +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes to any JSON pointer. + ## Exceptions - Throws [parse_error.107](../../home/exceptions.md#jsonexceptionparse_error107) if the given JSON pointer `s` is @@ -19,6 +23,10 @@ Create a JSON pointer according to the syntax described in - Throws [parse_error.108](../../home/exceptions.md#jsonexceptionparse_error108) if a tilde (`~`) in the given JSON pointer `s` is not followed by `0` (representing `~`) or `1` (representing `/`); see example below. +## Complexity + +Linear in the length of `s`. + ## Examples ??? example @@ -35,6 +43,11 @@ Create a JSON pointer according to the syntax described in --8<-- "examples/json_pointer.output" ``` +## See also + +- [JSON Pointer](../../features/json_pointer.md) - the article on JSON Pointer support +- [operator""_json_pointer](../operator_literal_json_pointer.md) user-defined string literal for JSON pointers + ## Version history - Added in version 2.0.0. diff --git a/docs/mkdocs/docs/api/json_pointer/operator_eq.md b/docs/mkdocs/docs/api/json_pointer/operator_eq.md index 807ae1d0c..a9f40891f 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_eq.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_eq.md @@ -77,6 +77,8 @@ tokens. Overload 2 is deprecated and will be removed in a future major version release. + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example "Example: (1) Comparing JSON pointers" @@ -107,6 +109,11 @@ tokens. --8<-- "examples/json_pointer__operator__equal_stringtype.output" ``` +## See also + +- [operator!=](operator_ne.md) compare for inequality +- [operator<=>](operator_spaceship.md) comparison: 3-way (C++20) + ## Version history 1. Added in version 2.1.0. Added C++20 member functions in version 3.11.2. diff --git a/docs/mkdocs/docs/api/json_pointer/operator_ne.md b/docs/mkdocs/docs/api/json_pointer/operator_ne.md index 1f3e3247e..77e6b92c8 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_ne.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_ne.md @@ -73,6 +73,8 @@ tokens. Overload 2 is deprecated and will be removed in a future major version release. + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example "Example: (1) Comparing JSON pointers" @@ -103,6 +105,11 @@ tokens. --8<-- "examples/json_pointer__operator__notequal_stringtype.output" ``` +## See also + +- [operator==](operator_eq.md) compare for equality +- [operator<=>](operator_spaceship.md) comparison: 3-way (C++20) + ## Version history 1. Added in version 2.1.0. diff --git a/docs/mkdocs/docs/api/json_pointer/operator_slash.md b/docs/mkdocs/docs/api/json_pointer/operator_slash.md index ed77b504b..e91f8a119 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_slash.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_slash.md @@ -35,6 +35,11 @@ json_pointer operator/(const json_pointer& lhs, std::size_t array_idx); 2. a new JSON pointer with unescaped `token` appended to `lhs` 3. a new JSON pointer with `array_idx` appended to `lhs` +## Exception safety + +Strong guarantee: if an exception is thrown, there are no changes to any JSON pointer. The operands are not modified; +a new JSON pointer is built from a copy of `lhs`. + ## Complexity 1. Linear in the length of `lhs` and `rhs`. @@ -57,6 +62,11 @@ json_pointer operator/(const json_pointer& lhs, std::size_t array_idx); --8<-- "examples/json_pointer__operator_add_binary.output" ``` +## See also + +- [operator/=](operator_slasheq.md) append to the end of the JSON pointer +- [push_back](push_back.md) append an unescaped token at the end of the pointer + ## Version history 1. Added in version 3.6.0. diff --git a/docs/mkdocs/docs/api/json_pointer/operator_slasheq.md b/docs/mkdocs/docs/api/json_pointer/operator_slasheq.md index 3518557d5..05e8ccbcf 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_slasheq.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_slasheq.md @@ -32,6 +32,13 @@ json_pointer& operator/=(std::size_t array_idx) 2. JSON pointer with `token` appended without escaping `token` 3. JSON pointer with `array_idx` appended +## Exception safety + +1. Basic guarantee: if an exception is thrown (for instance, if copying a reference token fails), the JSON pointer is + left in a valid state, but it may contain some of the reference tokens of `ptr`. +2. Strong guarantee: if an exception is thrown, there are no changes to the JSON pointer. +3. Strong guarantee: if an exception is thrown, there are no changes to the JSON pointer. + ## Complexity 1. Linear in the length of `ptr`. @@ -54,6 +61,11 @@ json_pointer& operator/=(std::size_t array_idx) --8<-- "examples/json_pointer__operator_add.output" ``` +## See also + +- [operator/](operator_slash.md) create JSON Pointer by appending +- [push_back](push_back.md) append an unescaped token at the end of the pointer + ## Version history 1. Added in version 3.6.0. diff --git a/docs/mkdocs/docs/api/json_pointer/operator_spaceship.md b/docs/mkdocs/docs/api/json_pointer/operator_spaceship.md new file mode 100644 index 000000000..2ec917b72 --- /dev/null +++ b/docs/mkdocs/docs/api/json_pointer/operator_spaceship.md @@ -0,0 +1,74 @@ +# nlohmann::json_pointer::operator<=> + +```cpp +// since C++20 +class json_pointer { + template + std::strong_ordering operator<=>(const json_pointer& rhs) const noexcept; // *NOPAD* +}; +``` + +3-way compares two JSON pointers by lexicographically comparing their sequences of reference tokens: corresponding +reference tokens are compared with `string_t`'s own `operator<=>`, and the first pair of tokens that differs +determines the result. If all corresponding reference tokens compare equal, the JSON pointer with fewer reference +tokens is ordered first. + +## Template parameters + +`RefStringTypeRhs` +: the string type of the right-hand side JSON pointer + +## Parameters + +`rhs` (in) +: JSON pointer to compare `*this` with + +## Return value + +the `std::strong_ordering` of the 3-way comparison of `*this` and `rhs` + +## Exception safety + +No-throw guarantee: this function never throws exceptions. + +## Complexity + +Linear in the number of reference tokens. + +## Notes + +!!! note "Ordering enables use as an associative container key" + + Together with [`operator==`](operator_eq.md), `operator<=>` makes `json_pointer` a `LessThanComparable` type, so + it can be used as the key type of ordered associative containers such as `std::map` or `std::set`. + +!!! note "Before C++20" + + Without C++20's three-way comparison, `json_pointer` provides a non-member `operator<` instead, which orders JSON + pointers the same way. JSON pointers can therefore be used as keys of ordered associative containers with any + supported C++ standard. + +## Examples + +??? example + + The example demonstrates 3-way comparing JSON pointers. + + ```cpp + --8<-- "examples/json_pointer__operator_spaceship.c++20.cpp" + ``` + + Output: + + ``` + --8<-- "examples/json_pointer__operator_spaceship.c++20.output" + ``` + +## See also + +- [operator==](operator_eq.md) compare: equal +- [operator!=](operator_ne.md) compare: not equal + +## Version history + +- Added in version 3.11.2. diff --git a/docs/mkdocs/docs/api/json_pointer/operator_string_t.md b/docs/mkdocs/docs/api/json_pointer/operator_string_t.md index 89898fa4f..9fd8bce94 100644 --- a/docs/mkdocs/docs/api/json_pointer/operator_string_t.md +++ b/docs/mkdocs/docs/api/json_pointer/operator_string_t.md @@ -26,6 +26,8 @@ operator string_t() const This function is deprecated in favor of [`to_string`](to_string.md) and will be removed in a future major version release. + See the [migration guide](../../integration/migration_guide.md#json-pointers) for how to update existing code. + ## Examples ??? example @@ -44,7 +46,8 @@ operator string_t() const ## See also -- [string_t](../basic_json/string_t.md)- type for strings +- [to_string](to_string.md) return a string representation of the JSON pointer +- [string_t](../basic_json/string_t.md) - type for strings ## Version history diff --git a/docs/mkdocs/docs/api/json_pointer/pop_back.md b/docs/mkdocs/docs/api/json_pointer/pop_back.md index 16b1cd4da..6646be44a 100644 --- a/docs/mkdocs/docs/api/json_pointer/pop_back.md +++ b/docs/mkdocs/docs/api/json_pointer/pop_back.md @@ -6,6 +6,10 @@ void pop_back(); Remove the last reference token. +## Exception safety + +Strong exception safety: if an exception occurs, the original value stays intact. + ## Exceptions Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent. @@ -30,6 +34,12 @@ Constant. --8<-- "examples/json_pointer__pop_back.output" ``` +## See also + +- [back](back.md) return last reference token +- [push_back](push_back.md) append an unescaped token at the end of the pointer +- [parent_pointer](parent_pointer.md) returns the parent of this JSON pointer + ## Version history Added in version 3.6.0. diff --git a/docs/mkdocs/docs/api/json_pointer/pop_front.md b/docs/mkdocs/docs/api/json_pointer/pop_front.md index e77980bb4..308a3cbdc 100644 --- a/docs/mkdocs/docs/api/json_pointer/pop_front.md +++ b/docs/mkdocs/docs/api/json_pointer/pop_front.md @@ -6,6 +6,10 @@ void pop_front(); Remove the first reference token. +## Exception safety + +Strong exception safety: if an exception occurs, the original value stays intact. + ## Exceptions Throws [out_of_range.405](../../home/exceptions.md#jsonexceptionout_of_range405) if the JSON pointer has no parent. @@ -30,6 +34,11 @@ Linear in the number of reference tokens in the `json_pointer`. --8<-- "examples/json_pointer__pop_front.output" ``` +## See also + +- [front](front.md) return first reference token +- [push_front](push_front.md) append an unescaped token at the start of the pointer + ## Version history - Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/json_pointer/push_back.md b/docs/mkdocs/docs/api/json_pointer/push_back.md index c1c19cb8d..f50f10924 100644 --- a/docs/mkdocs/docs/api/json_pointer/push_back.md +++ b/docs/mkdocs/docs/api/json_pointer/push_back.md @@ -13,6 +13,10 @@ Append an unescaped token at the end of the reference pointer. `token` (in) : token to add +## Exception safety + +Strong exception safety: if an exception occurs, the original value stays intact. + ## Complexity Amortized constant. @@ -33,6 +37,13 @@ Amortized constant. --8<-- "examples/json_pointer__push_back.output" ``` +## See also + +- [back](back.md) return last reference token +- [pop_back](pop_back.md) remove the last reference token +- [operator/=](operator_slasheq.md) append to the end of the JSON pointer +- [operator/](operator_slash.md) create JSON Pointer by appending + ## Version history - Added in version 3.6.0. diff --git a/docs/mkdocs/docs/api/json_pointer/push_front.md b/docs/mkdocs/docs/api/json_pointer/push_front.md index 387e86e48..67dd87384 100644 --- a/docs/mkdocs/docs/api/json_pointer/push_front.md +++ b/docs/mkdocs/docs/api/json_pointer/push_front.md @@ -13,6 +13,11 @@ Append an unescaped token at the start of the reference pointer. `token` (in) : token to add +## Exception safety + +Basic guarantee: if an exception is thrown (for instance, if copying the reference token fails), the JSON pointer is +left in a valid state, but its reference tokens may have changed. + ## Complexity Linear in the number of reference tokens in the `json_pointer`. @@ -33,6 +38,11 @@ Linear in the number of reference tokens in the `json_pointer`. --8<-- "examples/json_pointer__push_front.output" ``` +## See also + +- [front](front.md) return first reference token +- [pop_front](pop_front.md) remove the first reference token + ## Version history - Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/json_pointer/string_t.md b/docs/mkdocs/docs/api/json_pointer/string_t.md index c8527bc9c..6808ae540 100644 --- a/docs/mkdocs/docs/api/json_pointer/string_t.md +++ b/docs/mkdocs/docs/api/json_pointer/string_t.md @@ -23,6 +23,11 @@ See [`basic_json::string_t`](../basic_json/string_t.md) for more information. --8<-- "examples/json_pointer__string_t.output" ``` +## See also + +- [basic_json::string_t](../basic_json/string_t.md) type used to store JSON strings +- [to_string](to_string.md) return a string representation of the JSON pointer + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/json_pointer/to_string.md b/docs/mkdocs/docs/api/json_pointer/to_string.md index fae3abe5f..2f700e1db 100644 --- a/docs/mkdocs/docs/api/json_pointer/to_string.md +++ b/docs/mkdocs/docs/api/json_pointer/to_string.md @@ -10,6 +10,14 @@ Return a string representation of the JSON pointer. A string representation of the JSON pointer +## Exception safety + +Strong exception safety: if an exception occurs, the original value stays intact. + +## Complexity + +Linear in the total length of the reference tokens. + ## Notes For each JSON pointer `ptr`, it holds: @@ -34,6 +42,11 @@ ptr == json_pointer(ptr.to_string()); --8<-- "examples/json_pointer__to_string.output" ``` +## See also + +- [operator string_t](operator_string_t.md) return a string representation of the JSON pointer (deprecated) +- [operator<<](../operator_ltlt.md) write a JSON pointer to a stream + ## Version history - Since version 2.0.0. diff --git a/docs/mkdocs/docs/api/json_sax/binary.md b/docs/mkdocs/docs/api/json_sax/binary.md index fc0980e20..f5310390e 100644 --- a/docs/mkdocs/docs/api/json_sax/binary.md +++ b/docs/mkdocs/docs/api/json_sax/binary.md @@ -35,6 +35,12 @@ It is safe to move the passed binary value. --8<-- "examples/sax_parse__binary.output" ``` +## See also + +- [sax_parse](../basic_json/sax_parse.md) - SAX parser +- [SAX Interface](../../features/parsing/sax_interface.md) - the SAX interface article +- [Binary Values](../../features/binary_values.md) - the article on binary values + ## Version history - Added in version 3.8.0. diff --git a/docs/mkdocs/docs/api/json_sax/boolean.md b/docs/mkdocs/docs/api/json_sax/boolean.md index fdf294562..89abb67ba 100644 --- a/docs/mkdocs/docs/api/json_sax/boolean.md +++ b/docs/mkdocs/docs/api/json_sax/boolean.md @@ -31,6 +31,11 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [sax_parse](../basic_json/sax_parse.md) - SAX parser +- [SAX Interface](../../features/parsing/sax_interface.md) - the SAX interface article + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/end_array.md b/docs/mkdocs/docs/api/json_sax/end_array.md index 9c12e40a5..7010e7259 100644 --- a/docs/mkdocs/docs/api/json_sax/end_array.md +++ b/docs/mkdocs/docs/api/json_sax/end_array.md @@ -26,6 +26,11 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [start_array](start_array.md) - the beginning of an array was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/end_object.md b/docs/mkdocs/docs/api/json_sax/end_object.md index 601c94a4a..aaaec6d22 100644 --- a/docs/mkdocs/docs/api/json_sax/end_object.md +++ b/docs/mkdocs/docs/api/json_sax/end_object.md @@ -26,6 +26,12 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [start_object](start_object.md) - the beginning of an object was read +- [key](key.md) - an object key was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/index.md b/docs/mkdocs/docs/api/json_sax/index.md index d66b7a254..19d0a52ac 100644 --- a/docs/mkdocs/docs/api/json_sax/index.md +++ b/docs/mkdocs/docs/api/json_sax/index.md @@ -9,6 +9,27 @@ This class describes the SAX interface used by [sax_parse](../basic_json/sax_par different situations while the input is parsed. The boolean return value informs the parser whether to continue processing the input. +For instance, parsing the JSON text `{"a": [1, true]}` triggers the following callbacks, in order: + +```mermaid +sequenceDiagram + participant P as Parser + participant H as SAX handler + + P->>H: start_object(elements) + P->>H: key("a") + P->>H: start_array(elements) + P->>H: number_unsigned(1) + P->>H: boolean(true) + P->>H: end_array() + P->>H: end_object() +``` + +Note `elements` is passed as `#!cpp std::numeric_limits::max()` (i.e., "unknown") for JSON text input; +only binary formats such as CBOR or MessagePack may report the actual number of elements in `start_object`/ +`start_array`. Also note that `1` is reported via `number_unsigned` rather than `number_integer` because it has no +leading `-` sign. + ## Template parameters `BasicJsonType` diff --git a/docs/mkdocs/docs/api/json_sax/key.md b/docs/mkdocs/docs/api/json_sax/key.md index 31fd6c1d1..5ecea20f9 100644 --- a/docs/mkdocs/docs/api/json_sax/key.md +++ b/docs/mkdocs/docs/api/json_sax/key.md @@ -35,6 +35,12 @@ It is safe to move the passed object key value. --8<-- "examples/sax_parse.output" ``` +## See also + +- [start_object](start_object.md) - the beginning of an object was read +- [end_object](end_object.md) - the end of an object was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/null.md b/docs/mkdocs/docs/api/json_sax/null.md index 9354ede6c..ef5771094 100644 --- a/docs/mkdocs/docs/api/json_sax/null.md +++ b/docs/mkdocs/docs/api/json_sax/null.md @@ -26,6 +26,11 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [sax_parse](../basic_json/sax_parse.md) - SAX parser +- [SAX Interface](../../features/parsing/sax_interface.md) - the SAX interface article + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/number_float.md b/docs/mkdocs/docs/api/json_sax/number_float.md index 17799401e..d9c37c257 100644 --- a/docs/mkdocs/docs/api/json_sax/number_float.md +++ b/docs/mkdocs/docs/api/json_sax/number_float.md @@ -34,6 +34,12 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [number_integer](number_integer.md) - an integer number was read +- [number_unsigned](number_unsigned.md) - an unsigned integer number was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/number_integer.md b/docs/mkdocs/docs/api/json_sax/number_integer.md index 5c3cb4f31..c67f9a410 100644 --- a/docs/mkdocs/docs/api/json_sax/number_integer.md +++ b/docs/mkdocs/docs/api/json_sax/number_integer.md @@ -31,6 +31,12 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [number_unsigned](number_unsigned.md) - an unsigned integer number was read +- [number_float](number_float.md) - a floating-point number was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/number_unsigned.md b/docs/mkdocs/docs/api/json_sax/number_unsigned.md index 0ac250037..edb40d402 100644 --- a/docs/mkdocs/docs/api/json_sax/number_unsigned.md +++ b/docs/mkdocs/docs/api/json_sax/number_unsigned.md @@ -31,6 +31,12 @@ Whether parsing should proceed. --8<-- "examples/sax_parse.output" ``` +## See also + +- [number_integer](number_integer.md) - an integer number was read +- [number_float](number_float.md) - a floating-point number was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/parse_error.md b/docs/mkdocs/docs/api/json_sax/parse_error.md index e41cb67ff..ce90f4448 100644 --- a/docs/mkdocs/docs/api/json_sax/parse_error.md +++ b/docs/mkdocs/docs/api/json_sax/parse_error.md @@ -39,6 +39,12 @@ Whether parsing should proceed (**must return `#!cpp false`**). --8<-- "examples/sax_parse.output" ``` +## See also + +- [sax_parse](../basic_json/sax_parse.md) - SAX parser +- [Parsing and Exceptions](../../features/parsing/parse_exceptions.md) - the article on handling parse errors without + exceptions + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/start_array.md b/docs/mkdocs/docs/api/json_sax/start_array.md index 1a221565f..48557fa48 100644 --- a/docs/mkdocs/docs/api/json_sax/start_array.md +++ b/docs/mkdocs/docs/api/json_sax/start_array.md @@ -35,6 +35,11 @@ Binary formats may report the number of elements. --8<-- "examples/sax_parse.output" ``` +## See also + +- [end_array](end_array.md) - the end of an array was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/start_object.md b/docs/mkdocs/docs/api/json_sax/start_object.md index 5ae753805..3a569878f 100644 --- a/docs/mkdocs/docs/api/json_sax/start_object.md +++ b/docs/mkdocs/docs/api/json_sax/start_object.md @@ -35,6 +35,12 @@ Binary formats may report the number of elements. --8<-- "examples/sax_parse.output" ``` +## See also + +- [end_object](end_object.md) - the end of an object was read +- [key](key.md) - an object key was read +- [sax_parse](../basic_json/sax_parse.md) - SAX parser + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/json_sax/string.md b/docs/mkdocs/docs/api/json_sax/string.md index dcffb5f61..7e742ebcb 100644 --- a/docs/mkdocs/docs/api/json_sax/string.md +++ b/docs/mkdocs/docs/api/json_sax/string.md @@ -35,6 +35,11 @@ It is safe to move the passed string value. --8<-- "examples/sax_parse.output" ``` +## See also + +- [sax_parse](../basic_json/sax_parse.md) - SAX parser +- [SAX Interface](../../features/parsing/sax_interface.md) - the SAX interface article + ## Version history - Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/macros/index.md b/docs/mkdocs/docs/api/macros/index.md index bf773b5c4..6c11e77ec 100644 --- a/docs/mkdocs/docs/api/macros/index.md +++ b/docs/mkdocs/docs/api/macros/index.md @@ -26,6 +26,7 @@ header. See also the [macro overview page](../../features/macros.md). - [**JSON_HAS_CPP_11**
**JSON_HAS_CPP_14**
**JSON_HAS_CPP_17**
**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard - [**JSON_HAS_FILESYSTEM**
**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support - [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support +- [**JSON_HAS_STATIC_RTTI**](json_has_static_rtti.md) - control RTTI (run time type information) support - [**JSON_HAS_STD_FORMAT**](json_has_std_format.md) - control `std::format`/`std::formatter` support - [**JSON_HAS_THREE_WAY_COMPARISON**](json_has_three_way_comparison.md) - control 3-way comparison support - [**JSON_NO_IO**](json_no_io.md) - switch off functions relying on certain C++ I/O headers diff --git a/docs/mkdocs/docs/api/macros/json_assert.md b/docs/mkdocs/docs/api/macros/json_assert.md index 2d7b0c78a..5cd52a091 100644 --- a/docs/mkdocs/docs/api/macros/json_assert.md +++ b/docs/mkdocs/docs/api/macros/json_assert.md @@ -31,7 +31,7 @@ Therefore, assertions can be switched off by defining `NDEBUG`. ## Examples -??? example "Example 1: default behavior" +??? example "Example: default behavior" The following code will trigger an assertion at runtime: @@ -53,7 +53,7 @@ Therefore, assertions can be switched off by defining `NDEBUG`. Assertion failed: (m_value.object->find(key) != m_value.object->end()), function operator[], file json.hpp, line 2144. ``` -??? example "Example 2: user-defined behavior" +??? example "Example: user-defined behavior" The assertion reporting can be changed by defining `JSON_ASSERT(x)` differently. diff --git a/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md b/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md index 2301a0486..459818c87 100644 --- a/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md +++ b/docs/mkdocs/docs/api/macros/json_brace_init_copy_semantics.md @@ -70,7 +70,7 @@ The default value is `0` (disabled — existing behavior is preserved). ## Examples -??? example "Default behavior (macro not defined)" +??? example "Example: default behavior (macro not defined)" Without the macro, single-element brace initialization wraps the value in an array: @@ -88,7 +88,7 @@ The default value is `0` (disabled — existing behavior is preserved). } ``` -??? example "Opt-in copy semantics (macro defined to 1)" +??? example "Example: opt-in copy semantics (macro defined to 1)" With the macro, single-element brace initialization copies/moves the value: diff --git a/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md b/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md index f928f227e..486f3f34e 100644 --- a/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md +++ b/docs/mkdocs/docs/api/macros/json_diagnostic_positions.md @@ -81,7 +81,7 @@ When the macro is not defined, the library will define it to its default value. The output shows the start/end positions of all the objects and fields in the JSON string. -??? example "Example 2: using only diagnostic positions in exceptions" +??? example "Example: using only diagnostic positions in exceptions" ```cpp --8<-- "examples/diagnostic_positions_exception.cpp" @@ -95,7 +95,7 @@ When the macro is not defined, the library will define it to its default value. The output shows the exception with start/end positions only. -??? example "Example 3: using extended diagnostics with positions enabled in exceptions" +??? example "Example: using extended diagnostics with positions enabled in exceptions" ```cpp --8<-- "examples/diagnostics_extended_positions.cpp" diff --git a/docs/mkdocs/docs/api/macros/json_diagnostics.md b/docs/mkdocs/docs/api/macros/json_diagnostics.md index d60df5e44..c68b4380b 100644 --- a/docs/mkdocs/docs/api/macros/json_diagnostics.md +++ b/docs/mkdocs/docs/api/macros/json_diagnostics.md @@ -43,7 +43,7 @@ When the macro is not defined, the library will define it to its default value. ## Examples -??? example "Example 1: default behavior" +??? example "Example: default behavior" ```cpp --8<-- "examples/diagnostics_standard.cpp" @@ -57,7 +57,7 @@ When the macro is not defined, the library will define it to its default value. This exception can be hard to debug if storing the value `#!c "12"` and accessing it is further apart. -??? example "Example 2: extended diagnostic messages" +??? example "Example: extended diagnostic messages" ```cpp --8<-- "examples/diagnostics_extended.cpp" @@ -71,7 +71,7 @@ When the macro is not defined, the library will define it to its default value. Now the exception message contains a JSON Pointer `/address/housenumber` that indicates which value has the wrong type. -??? example "Example 3: using only diagnostic positions in exceptions" +??? example "Example: using only diagnostic positions in exceptions" ```cpp --8<-- "examples/diagnostic_positions_exception.cpp" diff --git a/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md b/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md index 2548a03fa..83c48515b 100644 --- a/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md +++ b/docs/mkdocs/docs/api/macros/json_disable_enum_serialization.md @@ -30,7 +30,7 @@ The default value is `0`. ## Examples -??? example "Example 1: Disabled behavior" +??? example "Example: Disabled behavior" The code below forces the library **not** to create default serialization/deserialization functions `from_json` and `to_json`, meaning the code below **does not** compile. @@ -57,7 +57,7 @@ The default value is `0`. } ``` -??? example "Example 2: Serialize enum macro" +??? example "Example: Serialize enum macro" The code below forces the library **not** to create default serialization/deserialization functions `from_json` and `to_json`, but uses [`NLOHMANN_JSON_SERIALIZE_ENUM`](nlohmann_json_serialize_enum.md) to parse and serialize the enum. @@ -90,7 +90,7 @@ The default value is `0`. } ``` -??? example "Example 3: User-defined serialization/deserialization functions" +??? example "Example: User-defined serialization/deserialization functions" The code below forces the library **not** to create default serialization/deserialization functions `from_json` and `to_json`, but uses user-defined functions to parse and serialize the enum. diff --git a/docs/mkdocs/docs/api/macros/json_has_cpp_11.md b/docs/mkdocs/docs/api/macros/json_has_cpp_11.md index 053214bb3..6ab33bfe0 100644 --- a/docs/mkdocs/docs/api/macros/json_has_cpp_11.md +++ b/docs/mkdocs/docs/api/macros/json_has_cpp_11.md @@ -40,6 +40,13 @@ The default value is detected based on preprocessor macros such as `#!cpp __cplu ... ``` +## See also + +- [JSON_HAS_FILESYSTEM / JSON_HAS_EXPERIMENTAL_FILESYSTEM](json_has_filesystem.md) - control `std::filesystem` support +- [JSON_HAS_RANGES](json_has_ranges.md) - control `std::ranges` support +- [JSON_HAS_THREE_WAY_COMPARISON](json_has_three_way_comparison.md) - control 3-way comparison support +- [JSON_HAS_STD_FORMAT](json_has_std_format.md) - control `std::format`/`std::formatter` support + ## Version history - Added in version 3.10.5. diff --git a/docs/mkdocs/docs/api/macros/json_has_filesystem.md b/docs/mkdocs/docs/api/macros/json_has_filesystem.md index 68eb3089b..fe843e5c1 100644 --- a/docs/mkdocs/docs/api/macros/json_has_filesystem.md +++ b/docs/mkdocs/docs/api/macros/json_has_filesystem.md @@ -52,6 +52,11 @@ The default value is detected based on the preprocessor macros `#!cpp __cpp_lib_ ... ``` +## See also + +- [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 / + JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard + ## Version history - Added in version 3.10.5. diff --git a/docs/mkdocs/docs/api/macros/json_has_ranges.md b/docs/mkdocs/docs/api/macros/json_has_ranges.md index c51fb4f34..0bb3c9b58 100644 --- a/docs/mkdocs/docs/api/macros/json_has_ranges.md +++ b/docs/mkdocs/docs/api/macros/json_has_ranges.md @@ -40,6 +40,13 @@ When the macro is not defined, the library will define it to its default value. ... ``` +## See also + +- [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 / + JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard +- [JSON_HAS_STD_FORMAT](json_has_std_format.md) - a similar feature-detection macro, for `std::format`/`std::formatter` + support + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/macros/json_has_static_rtti.md b/docs/mkdocs/docs/api/macros/json_has_static_rtti.md index 33d0703ab..a44a7c224 100644 --- a/docs/mkdocs/docs/api/macros/json_has_static_rtti.md +++ b/docs/mkdocs/docs/api/macros/json_has_static_rtti.md @@ -25,7 +25,12 @@ When the macro is not defined, the library will define it to its default value. ... ``` - + +## See also + +- [**operator ValueType**](../basic_json/operator_ValueType.md) - get a value (implicit); on C++17, this macro + controls whether `std::any` is excluded from its candidate types + ## Version history - Added in version 3.11.3. diff --git a/docs/mkdocs/docs/api/macros/json_has_std_format.md b/docs/mkdocs/docs/api/macros/json_has_std_format.md index 8f61d0fed..0691fe3cd 100644 --- a/docs/mkdocs/docs/api/macros/json_has_std_format.md +++ b/docs/mkdocs/docs/api/macros/json_has_std_format.md @@ -36,6 +36,10 @@ When the macro is not defined, the library will define it to its default value. ... ``` +## See also + +- [`std::formatter`](../basic_json/std_formatter.md) - format JSON values with `std::format` + ## Version history - Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/json_has_three_way_comparison.md b/docs/mkdocs/docs/api/macros/json_has_three_way_comparison.md index f52070ebf..a1c2cdb58 100644 --- a/docs/mkdocs/docs/api/macros/json_has_three_way_comparison.md +++ b/docs/mkdocs/docs/api/macros/json_has_three_way_comparison.md @@ -27,6 +27,11 @@ When the macro is not defined, the library will define it to its default value. ... ``` +## See also + +- [**operator<=>**](../basic_json/operator_spaceship.md) - 3-way compare JSON values +- [**operator==**](../json_pointer/operator_eq.md) - compare JSON pointers for equality + ## Version history - Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/macros/json_no_io.md b/docs/mkdocs/docs/api/macros/json_no_io.md index ef37384a5..ed76672ac 100644 --- a/docs/mkdocs/docs/api/macros/json_no_io.md +++ b/docs/mkdocs/docs/api/macros/json_no_io.md @@ -30,6 +30,11 @@ By default, `#!cpp JSON_NO_IO` is not defined. ... ``` +## See also + +- [**operator<<**](../operator_ltlt.md) - serialize to stream +- [**operator>>**](../operator_gtgt.md) - deserialize from stream + ## Version history - Added in version 3.10.0. diff --git a/docs/mkdocs/docs/api/macros/json_no_thread_local.md b/docs/mkdocs/docs/api/macros/json_no_thread_local.md index 0a001ac36..f4fb28dbb 100644 --- a/docs/mkdocs/docs/api/macros/json_no_thread_local.md +++ b/docs/mkdocs/docs/api/macros/json_no_thread_local.md @@ -43,6 +43,10 @@ Copying and comparing fall back to working without the call stack there, as they ... ``` +## See also + +- [FAQ: Thread safety](../../home/faq.md#thread-safety) + ## Version history -- Added in version 3.12.1. +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/json_precise_stream_position.md b/docs/mkdocs/docs/api/macros/json_precise_stream_position.md index 5710e9975..b3145fc66 100644 --- a/docs/mkdocs/docs/api/macros/json_precise_stream_position.md +++ b/docs/mkdocs/docs/api/macros/json_precise_stream_position.md @@ -79,7 +79,7 @@ The default value is `0` (disabled — existing behavior is preserved). ## Examples -??? example "Default behavior (macro not defined)" +??? example "Example: default behavior (macro not defined)" Without the macro, the character after a number is consumed: @@ -99,7 +99,7 @@ The default value is `0` (disabled — existing behavior is preserved). } ``` -??? example "Opt-in precise stream position (macro defined to 1)" +??? example "Example: opt-in precise stream position (macro defined to 1)" With the macro, the stream is positioned right after the number: diff --git a/docs/mkdocs/docs/api/macros/json_skip_library_version_check.md b/docs/mkdocs/docs/api/macros/json_skip_library_version_check.md index 37e91b3c6..88f272334 100644 --- a/docs/mkdocs/docs/api/macros/json_skip_library_version_check.md +++ b/docs/mkdocs/docs/api/macros/json_skip_library_version_check.md @@ -24,7 +24,7 @@ By default, the macro is not defined. ## Examples -??? example +??? example "Example: switch off the version check" The code below switches off the warning about including a different version of the library. @@ -35,7 +35,7 @@ By default, the macro is not defined. ... ``` -!!! example +??? example "Example: warning about a different library version" The following warning will be shown in case a different version of the library was already included: @@ -43,6 +43,11 @@ By default, the macro is not defined. Already included a different version of the library! ``` +## See also + +- [NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR, + NLOHMANN_JSON_VERSION_PATCH](nlohmann_json_version_major.md) - library version information + ## Version history -Added in version 3.11.0. +- Added in version 3.11.0. diff --git a/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md b/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md index 52cdbd172..f5702a454 100644 --- a/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md +++ b/docs/mkdocs/docs/api/macros/json_skip_unsupported_compiler_check.md @@ -28,6 +28,11 @@ By default, the macro is not defined. ... ``` +## See also + +- [JSON_HAS_CPP_11 / JSON_HAS_CPP_14 / JSON_HAS_CPP_17 / JSON_HAS_CPP_20 / JSON_HAS_CPP_23 / + JSON_HAS_CPP_26](json_has_cpp_11.md) - set supported C++ standard + ## Version history -Added in version 3.2.0. +- Added in version 3.2.0. diff --git a/docs/mkdocs/docs/api/macros/json_strict_nul_handling.md b/docs/mkdocs/docs/api/macros/json_strict_nul_handling.md index f22395d3b..9f695bad8 100644 --- a/docs/mkdocs/docs/api/macros/json_strict_nul_handling.md +++ b/docs/mkdocs/docs/api/macros/json_strict_nul_handling.md @@ -82,7 +82,7 @@ The default value is `0` (disabled — existing behavior is preserved). ## Examples -??? example "Default behavior (macro not defined)" +??? example "Example: default behavior (macro not defined)" Without the macro, a NUL byte silently ends parsing at that point: @@ -98,7 +98,7 @@ The default value is `0` (disabled — existing behavior is preserved). } ``` -??? example "Opt-in strict handling (macro defined to 1)" +??? example "Example: opt-in strict handling (macro defined to 1)" With the macro, a NUL byte is rejected like any other unexpected byte: @@ -121,6 +121,7 @@ The default value is `0` (disabled — existing behavior is preserved). ## See also +- [:simple-cmake: JSON_StrictNulHandling](../../integration/cmake.md#json_strictnulhandling) - CMake option to control the macro - [FAQ: NUL bytes in the input](../../home/faq.md#nul-bytes-in-the-input) - [**parse**](../basic_json/parse.md) - deserialize from a compatible input - [**accept**](../basic_json/accept.md) - check if the input is valid JSON diff --git a/docs/mkdocs/docs/api/macros/json_use_global_udls.md b/docs/mkdocs/docs/api/macros/json_use_global_udls.md index 3110d4662..f89fdb000 100644 --- a/docs/mkdocs/docs/api/macros/json_use_global_udls.md +++ b/docs/mkdocs/docs/api/macros/json_use_global_udls.md @@ -26,6 +26,8 @@ When the macro is not defined, the library will define it to its default value. To prepare existing code, define `JSON_USE_GLOBAL_UDLS` to `0` and bring the string literals into scope where needed. Refer to any of the [string literals](#see-also) for details. + See the [migration guide](../../integration/migration_guide.md#import-namespace-literals-for-udls) for how to update existing code. + !!! hint "CMake option" The placement of user-defined string literals can also be controlled with the CMake option @@ -34,7 +36,7 @@ When the macro is not defined, the library will define it to its default value. ## Examples -??? example "Example 1: Default behavior" +??? example "Example: Default behavior" The code below shows the default behavior using the `_json` UDL. @@ -57,7 +59,7 @@ When the macro is not defined, the library will define it to its default value. 42 ``` -??? example "Example 2: Namespaced UDLs" +??? example "Example: Namespaced UDLs" The code below shows how UDLs need to be brought into scope before using `_json` when `JSON_USE_GLOBAL_UDLS` is defined to `0`. diff --git a/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md b/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md index e3d5fb29d..5b74f1ff7 100644 --- a/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md +++ b/docs/mkdocs/docs/api/macros/json_use_implicit_conversions.md @@ -24,6 +24,8 @@ By default, implicit conversions are enabled. You can prepare existing code by already defining `JSON_USE_IMPLICIT_CONVERSIONS` to `0` and replace any implicit conversions with calls to [`get`](../basic_json/get.md). + See the [migration guide](../../integration/migration_guide.md#replace-implicit-conversions) for how to update existing code. + !!! tip "Automatic migration" The community-maintained clang-tidy check `modernize-nlohmann-json-explicit-conversions` rewrites implicit diff --git a/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md b/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md index f026a9825..b6efd8dbd 100644 --- a/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md +++ b/docs/mkdocs/docs/api/macros/json_use_legacy_discarded_value_comparison.md @@ -53,6 +53,8 @@ When the macro is not defined, the library will define it to its default value. New code should not depend on it and existing code should try to remove or rewrite expressions relying on it. + See the [migration guide](../../integration/migration_guide.md#miscellaneous-functions) for how to update existing code. + !!! hint "CMake option" Legacy comparison can also be controlled with the CMake option diff --git a/docs/mkdocs/docs/api/macros/json_use_simdutf.md b/docs/mkdocs/docs/api/macros/json_use_simdutf.md index 611c1e9f1..99dc09892 100644 --- a/docs/mkdocs/docs/api/macros/json_use_simdutf.md +++ b/docs/mkdocs/docs/api/macros/json_use_simdutf.md @@ -62,9 +62,15 @@ By default, `#!cpp JSON_USE_SIMDUTF` is not defined and the portable C++11 scala !!! hint "Testing this configuration" - The unit tests can be built against the simdutf backend with the CMake option `JSON_TestSimdutf` (`OFF` by - default), which fetches simdutf and defines `JSON_USE_SIMDUTF` for every test target. The `ci_test_simdutf` target - runs the whole test suite in that configuration. + The unit tests can be built against the simdutf backend with the CMake option + [`JSON_TestSimdutf`](../../integration/cmake.md#json_testsimdutf) (`OFF` by default), which fetches simdutf and + defines `JSON_USE_SIMDUTF` for every test target. The `ci_test_simdutf` target runs the whole test suite in that + configuration. + +## See also + +- [:simple-cmake: JSON_TestSimdutf](../../integration/cmake.md#json_testsimdutf) - CMake option to build the unit + tests against the simdutf backend ## Version history diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md b/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md index 8c549d137..f6a01af5b 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_derived_type.md @@ -149,7 +149,7 @@ void to_json(BasicJsonType& j, const B& b) { ## Examples -??? example "NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE" +??? example "Example: (1) NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE" Consider the following complete example: diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md b/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md index deef3fec9..3db7722d8 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_type_intrusive.md @@ -83,7 +83,7 @@ See the examples below for the concrete generated code. ## Examples -??? example "Example (1): NLOHMANN_DEFINE_TYPE_INTRUSIVE" +??? example "Example: (1) NLOHMANN_DEFINE_TYPE_INTRUSIVE" Consider the following complete example: @@ -112,7 +112,7 @@ See the examples below for the concrete generated code. --8<-- "examples/nlohmann_define_type_intrusive_explicit.cpp" ``` -??? example "Example (2): NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT" +??? example "Example: (2) NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT" Consider the following complete example: @@ -142,7 +142,7 @@ See the examples below for the concrete generated code. Note how a default-initialized `person` object is used in the `from_json` to fill missing values. -??? example "Example (3): NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE" +??? example "Example: (3) NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE" Consider the following complete example: ```cpp hl_lines="22" diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md b/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md index 6a29c9e66..744a513b0 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_type_non_intrusive.md @@ -82,7 +82,7 @@ See the examples below for the concrete generated code. ## Examples -??? example "Example (1): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE" +??? example "Example: (1) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE" Consider the following complete example: @@ -110,7 +110,7 @@ See the examples below for the concrete generated code. --8<-- "examples/nlohmann_define_type_non_intrusive_explicit.cpp" ``` -??? example "Example (2): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT" +??? example "Example: (2) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT" Consider the following complete example: @@ -141,7 +141,7 @@ See the examples below for the concrete generated code. Note how a default-initialized `person` object is used in the `from_json` to fill missing values. -??? example "Example (3): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE" +??? example "Example: (3) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE" Consider the following complete example: diff --git a/docs/mkdocs/docs/api/macros/nlohmann_define_type_with_names.md b/docs/mkdocs/docs/api/macros/nlohmann_define_type_with_names.md index 9ce239645..9ee23c6dd 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_define_type_with_names.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_define_type_with_names.md @@ -45,7 +45,7 @@ For further information please refer to the corresponding macros without `WITH_N ## Examples -??? example "Example (1): NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES" +??? example "Example: NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_NAMES" Consider the following complete example: @@ -73,6 +73,21 @@ For further information please refer to the corresponding macros without `WITH_N --8<-- "examples/nlohmann_define_type_non_intrusive_with_names_explicit.cpp" ``` +## See also + +- [NLOHMANN_DEFINE_TYPE_INTRUSIVE, NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_type_intrusive.md) - the macros these variants add + custom JSON key names to +- [NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE, NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_type_non_intrusive.md) - the macros these + variants add custom JSON key names to +- [NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE, NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE, NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT, + NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE](nlohmann_define_derived_type.md) - similar macros for + derived types, also available with custom names +- [Arbitrary Type Conversions](../../features/arbitrary_types.md) - overview of type conversion mechanisms + ## Version history -1. Added in version 3.13.0. +- Added in version 3.13.0. diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md index 915a20a5f..626055fdf 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum.md @@ -44,7 +44,7 @@ inline void from_json(const BasicJsonType& j, type& e); ## Examples -??? example "Example 1: Basic usage" +??? example "Example: Basic usage" The example shows how `NLOHMANN_JSON_SERIALIZE_ENUM` can be used to serialize/deserialize both classical enums and C++11 enum classes: @@ -59,7 +59,7 @@ inline void from_json(const BasicJsonType& j, type& e); --8<-- "examples/nlohmann_json_serialize_enum.output" ``` -??? example "Example 2: Multiple conversions for one enumerator" +??? example "Example: Multiple conversions for one enumerator" The example shows how to use multiple conversions for a single enumerator. In the example, `Color::red` will always be *serialized* to `"red"`, because the first occurring conversion. The second conversion, however, offers an diff --git a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md index 73a3a7da4..4697c5a95 100644 --- a/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md +++ b/docs/mkdocs/docs/api/macros/nlohmann_json_serialize_enum_strict.md @@ -47,7 +47,7 @@ inline void from_json(const BasicJsonType& j, type& e); ## Examples -??? example "Example 1: Basic usage" +??? example "Example: Basic usage" The example shows how `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` can be used to serialize/deserialize both classical enums and C++11 enum classes: @@ -62,7 +62,7 @@ inline void from_json(const BasicJsonType& j, type& e); --8<-- "examples/nlohmann_json_serialize_enum_strict.output" ``` -??? example "Example 2: Multiple conversions for one enumerator" +??? example "Example: Multiple conversions for one enumerator" The example shows how to use multiple conversions for a single enumerator. In the example, `Color::red` will always be *serialized* to `"red"`, because the first occurring conversion. The second conversion, however, offers an @@ -78,7 +78,7 @@ inline void from_json(const BasicJsonType& j, type& e); --8<-- "examples/nlohmann_json_serialize_enum_strict_2.output" ``` -??? example "Example 3: exceptions on invalid serialization" +??? example "Example: exceptions on invalid serialization" The example shows how an invalid serialization causes an exception to be thrown. In the example, Color::unknown is not defined in the mapping used to call `NLOHMANN_JSON_SERIALIZE_ENUM_STRICT` diff --git a/docs/mkdocs/docs/api/operator_gtgt.md b/docs/mkdocs/docs/api/operator_gtgt.md index 0173b9fb3..c60929c27 100644 --- a/docs/mkdocs/docs/api/operator_gtgt.md +++ b/docs/mkdocs/docs/api/operator_gtgt.md @@ -87,6 +87,8 @@ being read. been deprecated in version 3.0.0. It will be removed in version 4.0.0. Please replace calls like `#!cpp j << i;` with `#!cpp i >> j;`. + See the [migration guide](../integration/migration_guide.md#parsing) for how to update existing code. + ## Examples ??? example diff --git a/docs/mkdocs/docs/api/operator_literal_json.md b/docs/mkdocs/docs/api/operator_literal_json.md index babce5799..8e0555e5c 100644 --- a/docs/mkdocs/docs/api/operator_literal_json.md +++ b/docs/mkdocs/docs/api/operator_literal_json.md @@ -18,7 +18,8 @@ using namespace nlohmann; ``` This is suggested to ease migration to the next major version release of the library. See -[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. +[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) and the +[migration guide](../integration/migration_guide.md#import-namespace-literals-for-udls) for details. ## Parameters @@ -64,4 +65,4 @@ Linear. - Added in version 1.0.0. - Moved to namespace `nlohmann::literals::json_literals` in 3.11.0. -- Added `char8_t*` overload in 3.13.0. +- Added `char8_t*` overload in version 3.13.0. diff --git a/docs/mkdocs/docs/api/operator_literal_json_pointer.md b/docs/mkdocs/docs/api/operator_literal_json_pointer.md index e1b729467..da2b1a74b 100644 --- a/docs/mkdocs/docs/api/operator_literal_json_pointer.md +++ b/docs/mkdocs/docs/api/operator_literal_json_pointer.md @@ -17,7 +17,8 @@ using namespace nlohmann::literals::json_literals; using namespace nlohmann; ``` This is suggested to ease migration to the next major version release of the library. See -[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) for details. +[`JSON_USE_GLOBAL_UDLS`](macros/json_use_global_udls.md#notes) and the +[migration guide](../integration/migration_guide.md#import-namespace-literals-for-udls) for details. ## Parameters @@ -63,4 +64,4 @@ Linear. - Added in version 2.0.0. - Moved to namespace `nlohmann::literals::json_literals` in 3.11.0. -- Added `char8_t*` overload in 3.13.0. +- Added `char8_t*` overload in version 3.13.0. diff --git a/docs/mkdocs/docs/api/operator_ltlt.md b/docs/mkdocs/docs/api/operator_ltlt.md index 1f99493d9..da53d7ee1 100644 --- a/docs/mkdocs/docs/api/operator_ltlt.md +++ b/docs/mkdocs/docs/api/operator_ltlt.md @@ -51,6 +51,8 @@ Linear. `#!cpp std::ostream& operator>>(const basic_json& j, std::ostream& o)` which has been deprecated in version 3.0.0. It will be removed in version 4.0.0. Please replace calls like `#!cpp j >> o;` with `#!cpp o << j;`. + See the [migration guide](../integration/migration_guide.md#miscellaneous-functions) for how to update existing code. + ## Examples ??? example "Example: (1) serialize JSON value to stream" diff --git a/docs/mkdocs/docs/api/ordered_map.md b/docs/mkdocs/docs/api/ordered_map.md index df21175d0..9d67c5249 100644 --- a/docs/mkdocs/docs/api/ordered_map.md +++ b/docs/mkdocs/docs/api/ordered_map.md @@ -94,8 +94,8 @@ This differs from `#!cpp std::map`, where the same operations are O(log n). | 16 000 | 3.3 ms | 181.6 ms | 54× | If key order matters for objects of that size, consider a container with a lookup index, such as - [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) - ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)), as the object type -- see + [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) + ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)), as the object type -- see [object order](../features/object_order.md). ## Examples diff --git a/docs/mkdocs/docs/community/assurance_case.md b/docs/mkdocs/docs/community/assurance_case.md index 10f4689c1..9d9712a03 100644 --- a/docs/mkdocs/docs/community/assurance_case.md +++ b/docs/mkdocs/docs/community/assurance_case.md @@ -30,6 +30,17 @@ that an attacker controls, passed to [`parse`](../api/basic_json/parse.md), [`ac not a security boundary. Such preconditions are checked with [runtime assertions](../features/assertions.md) in debug builds; functions such as [`at`](../api/basic_json/at.md) offer checked access with exceptions. +```mermaid +flowchart LR + A[Untrusted input] --> B[Parser] + A --> C[SAX interface] + A --> D[Binary readers] + B --> E["Value tree (basic_json)"] + C --> E + D --> E + E --> F[Trusted caller] +``` + ## Secure design - **Strict parsing.** The parser accepts exactly the JSON grammar of [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259). diff --git a/docs/mkdocs/docs/css/custom.css b/docs/mkdocs/docs/css/custom.css index 8940a782e..1fec0e57c 100644 --- a/docs/mkdocs/docs/css/custom.css +++ b/docs/mkdocs/docs/css/custom.css @@ -2,3 +2,19 @@ .md-typeset code, .md-typeset pre { font-variant-ligatures: common-ligatures; } + +/* badge after version numbers newer than the latest release (hooks/unreleased_versions.py) */ +.md-typeset .unreleased-version { + display: inline-block; + padding: 0 .5em; + border: .05rem solid var(--md-accent-fg-color); + border-radius: 1em; + background-color: var(--md-accent-fg-color--transparent); + color: var(--md-typeset-color); + font-size: .7em; + font-weight: 700; + line-height: 1.6; + vertical-align: .1em; + white-space: nowrap; + cursor: help; +} diff --git a/docs/mkdocs/docs/examples/accept__iterator_pair.cpp b/docs/mkdocs/docs/examples/accept__iterator_pair.cpp new file mode 100644 index 000000000..dc7320de6 --- /dev/null +++ b/docs/mkdocs/docs/examples/accept__iterator_pair.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + // a buffer containing a JSON text followed by more data + std::vector input = {'[', '1', ',', '2', ',', '3', ']', 'o', 't', 'h', 'e', 'r'}; + + std::cout << std::boolalpha + << json::accept(input.begin(), input.begin() + 7) << ' ' + << json::accept(input.begin(), input.end()) << '\n'; +} diff --git a/docs/mkdocs/docs/examples/accept__iterator_pair.output b/docs/mkdocs/docs/examples/accept__iterator_pair.output new file mode 100644 index 000000000..836a5934c --- /dev/null +++ b/docs/mkdocs/docs/examples/accept__iterator_pair.output @@ -0,0 +1 @@ +true false diff --git a/docs/mkdocs/docs/examples/basic_json__BasicJsonType.cpp b/docs/mkdocs/docs/examples/basic_json__BasicJsonType.cpp new file mode 100644 index 000000000..562d45b9f --- /dev/null +++ b/docs/mkdocs/docs/examples/basic_json__BasicJsonType.cpp @@ -0,0 +1,22 @@ +#include +#include + +using json = nlohmann::json; +using ordered_json = nlohmann::ordered_json; + +int main() +{ + // create an ordered_json value; insertion order is preserved + ordered_json oj = {{"c", 3}, {"a", 1}, {"b", 2}}; + + // convert to json -- overload (4) is used; keys end up sorted + json j(oj); + + // convert back to ordered_json -- the original insertion order is lost, + // because it was already given up when converting to json + ordered_json oj2(j); + + std::cout << oj << '\n'; + std::cout << j << '\n'; + std::cout << oj2 << '\n'; +} diff --git a/docs/mkdocs/docs/examples/basic_json__BasicJsonType.output b/docs/mkdocs/docs/examples/basic_json__BasicJsonType.output new file mode 100644 index 000000000..ab9841756 --- /dev/null +++ b/docs/mkdocs/docs/examples/basic_json__BasicJsonType.output @@ -0,0 +1,3 @@ +{"c":3,"a":1,"b":2} +{"a":1,"b":2,"c":3} +{"a":1,"b":2,"c":3} diff --git a/docs/mkdocs/docs/examples/basic_json__CompatibleType.cpp b/docs/mkdocs/docs/examples/basic_json__CompatibleType.cpp index f0d0cc1e7..130ef6aec 100644 --- a/docs/mkdocs/docs/examples/basic_json__CompatibleType.cpp +++ b/docs/mkdocs/docs/examples/basic_json__CompatibleType.cpp @@ -44,7 +44,7 @@ int main() // create an object from std::unordered_multimap std::unordered_multimap c_ummap { - {"one", true}, {"two", true}, {"three", false}, {"three", true} + {"one", true}, {"two", true}, {"three", false}, {"three", false} }; json j_ummap(c_ummap); // only one entry for key "three" is used @@ -92,7 +92,7 @@ int main() json j_set(c_set); // only one entry for "one" is used // create an array from std::unordered_set - std::unordered_set c_uset {"one", "two", "three", "four", "one"}; + std::unordered_set c_uset {"one", "one"}; json j_uset(c_uset); // only one entry for "one" is used // create an array from std::multiset @@ -100,7 +100,7 @@ int main() json j_mset(c_mset); // both entries for "one" are used // create an array from std::unordered_multiset - std::unordered_multiset c_umset {"one", "two", "one", "four"}; + std::unordered_multiset c_umset {"one", "one"}; json j_umset(c_umset); // both entries for "one" are used // serialize the JSON arrays diff --git a/docs/mkdocs/docs/examples/basic_json__CompatibleType.output b/docs/mkdocs/docs/examples/basic_json__CompatibleType.output index 2337e81fb..558d992a6 100644 --- a/docs/mkdocs/docs/examples/basic_json__CompatibleType.output +++ b/docs/mkdocs/docs/examples/basic_json__CompatibleType.output @@ -12,9 +12,9 @@ [12345678909876,23456789098765,34567890987654,45678909876543] [1,2,3,4] ["four","one","three","two"] -["four","three","two","one"] +["one"] ["four","one","one","two"] -["four","two","one","one"] +["one","one"] "The quick brown fox jumps over the lazy dog." "The quick brown fox jumps over the lazy dog." diff --git a/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.cpp new file mode 100644 index 000000000..ef2a9cdcb --- /dev/null +++ b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.cpp @@ -0,0 +1,23 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +int main() +{ + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // create containers without and with a subtype + auto c1 = byte_container_with_subtype(bytes); + auto c2 = byte_container_with_subtype(bytes); + auto c3 = byte_container_with_subtype(bytes, 42); + auto c4 = byte_container_with_subtype(bytes, 42); + auto c5 = byte_container_with_subtype(bytes, 23); + + std::cout << std::boolalpha + << "c1 == c2: " << (c1 == c2) << '\n' + << "c1 == c3: " << (c1 == c3) << '\n' + << "c3 == c4: " << (c3 == c4) << '\n' + << "c3 == c5: " << (c3 == c5) << std::endl; +} diff --git a/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.output new file mode 100644 index 000000000..32a281680 --- /dev/null +++ b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__equal.output @@ -0,0 +1,4 @@ +c1 == c2: true +c1 == c3: false +c3 == c4: true +c3 == c5: false diff --git a/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.cpp b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.cpp new file mode 100644 index 000000000..c7c104342 --- /dev/null +++ b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.cpp @@ -0,0 +1,23 @@ +#include +#include + +// define a byte container based on std::vector +using byte_container_with_subtype = nlohmann::byte_container_with_subtype>; + +int main() +{ + std::vector bytes = {{0xca, 0xfe, 0xba, 0xbe}}; + + // create containers without and with a subtype + auto c1 = byte_container_with_subtype(bytes); + auto c2 = byte_container_with_subtype(bytes); + auto c3 = byte_container_with_subtype(bytes, 42); + auto c4 = byte_container_with_subtype(bytes, 42); + auto c5 = byte_container_with_subtype(bytes, 23); + + std::cout << std::boolalpha + << "c1 != c2: " << (c1 != c2) << '\n' + << "c1 != c3: " << (c1 != c3) << '\n' + << "c3 != c4: " << (c3 != c4) << '\n' + << "c3 != c5: " << (c3 != c5) << std::endl; +} diff --git a/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.output b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.output new file mode 100644 index 000000000..61fcbbc1c --- /dev/null +++ b/docs/mkdocs/docs/examples/byte_container_with_subtype__operator__notequal.output @@ -0,0 +1,4 @@ +c1 != c2: false +c1 != c3: true +c3 != c4: false +c3 != c5: true diff --git a/docs/mkdocs/docs/examples/flatten__empty.cpp b/docs/mkdocs/docs/examples/flatten__empty.cpp new file mode 100644 index 000000000..1dd52d551 --- /dev/null +++ b/docs/mkdocs/docs/examples/flatten__empty.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a JSON value with an empty object and an empty array + json j = + { + {"empty_object", json::object()}, + {"empty_array", json::array()}, + {"name", "Niels"} + }; + + // call flatten() + json flattened = j.flatten(); + std::cout << std::setw(4) << flattened << "\n\n"; + + // the empty containers cannot be restored by unflatten() + std::cout << std::setw(4) << flattened.unflatten() << '\n'; +} diff --git a/docs/mkdocs/docs/examples/flatten__empty.output b/docs/mkdocs/docs/examples/flatten__empty.output new file mode 100644 index 000000000..ad5230f2c --- /dev/null +++ b/docs/mkdocs/docs/examples/flatten__empty.output @@ -0,0 +1,11 @@ +{ + "/empty_array": null, + "/empty_object": null, + "/name": "Niels" +} + +{ + "empty_array": null, + "empty_object": null, + "name": "Niels" +} diff --git a/docs/mkdocs/docs/examples/get__BasicJsonType.cpp b/docs/mkdocs/docs/examples/get__BasicJsonType.cpp new file mode 100644 index 000000000..d63458c0b --- /dev/null +++ b/docs/mkdocs/docs/examples/get__BasicJsonType.cpp @@ -0,0 +1,17 @@ +#include +#include + +using json = nlohmann::json; +using ordered_json = nlohmann::ordered_json; + +int main() +{ + // create a JSON value + json j = {{"one", 1}, {"two", 2}, {"three", 3}}; + + // convert to a different basic_json specialization + ordered_json oj = j.get(); + + std::cout << j << '\n'; + std::cout << oj << '\n'; +} diff --git a/docs/mkdocs/docs/examples/get__BasicJsonType.output b/docs/mkdocs/docs/examples/get__BasicJsonType.output new file mode 100644 index 000000000..85940d5ab --- /dev/null +++ b/docs/mkdocs/docs/examples/get__BasicJsonType.output @@ -0,0 +1,2 @@ +{"one":1,"three":3,"two":2} +{"one":1,"three":3,"two":2} diff --git a/docs/mkdocs/docs/examples/get__ValueType_const.cpp b/docs/mkdocs/docs/examples/get__ValueType_const.cpp index 7a703aaeb..7b0ca47bb 100644 --- a/docs/mkdocs/docs/examples/get__ValueType_const.cpp +++ b/docs/mkdocs/docs/examples/get__ValueType_const.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include using json = nlohmann::json; @@ -29,7 +29,7 @@ int main() auto v5 = json_types["number"]["floating-point"].get(); auto v6 = json_types["string"].get(); auto v7 = json_types["array"].get>(); - auto v8 = json_types.get>(); + auto v8 = json_types.get>(); // print the conversion results std::cout << v1 << '\n'; diff --git a/docs/mkdocs/docs/examples/get__ValueType_const.output b/docs/mkdocs/docs/examples/get__ValueType_const.output index e7e9b5d59..72a2147f6 100644 --- a/docs/mkdocs/docs/examples/get__ValueType_const.output +++ b/docs/mkdocs/docs/examples/get__ValueType_const.output @@ -4,8 +4,8 @@ Hello, world! 1 2 3 4 5 -number: {"floating-point":17.23,"integer":42} -null: null -string: "Hello, world!" -boolean: true array: [1,2,3,4,5] +boolean: true +null: null +number: {"floating-point":17.23,"integer":42} +string: "Hello, world!" diff --git a/docs/mkdocs/docs/examples/get_to.cpp b/docs/mkdocs/docs/examples/get_to.cpp index 358c8d43a..cdbe347c0 100644 --- a/docs/mkdocs/docs/examples/get_to.cpp +++ b/docs/mkdocs/docs/examples/get_to.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include using json = nlohmann::json; @@ -28,7 +28,7 @@ int main() int v5; std::string v6; std::vector v7; - std::unordered_map v8; + std::map v8; // use explicit conversions json_types["boolean"].get_to(v1); diff --git a/docs/mkdocs/docs/examples/get_to.output b/docs/mkdocs/docs/examples/get_to.output index e7e9b5d59..72a2147f6 100644 --- a/docs/mkdocs/docs/examples/get_to.output +++ b/docs/mkdocs/docs/examples/get_to.output @@ -4,8 +4,8 @@ Hello, world! 1 2 3 4 5 -number: {"floating-point":17.23,"integer":42} -null: null -string: "Hello, world!" -boolean: true array: [1,2,3,4,5] +boolean: true +null: null +number: {"floating-point":17.23,"integer":42} +string: "Hello, world!" diff --git a/docs/mkdocs/docs/examples/is_discarded__parse.cpp b/docs/mkdocs/docs/examples/is_discarded__parse.cpp new file mode 100644 index 000000000..feaca2363 --- /dev/null +++ b/docs/mkdocs/docs/examples/is_discarded__parse.cpp @@ -0,0 +1,22 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // parsing invalid JSON without exceptions yields a discarded value + json j_invalid = json::parse("[1,2,3", nullptr, false); + + // a callback that discards the top-level value does not leave it + // "discarded" -- it is replaced by null instead + json j_discarded_by_callback = json::parse("[1,2,3]", [](int /*depth*/, json::parse_event_t event, json& /*parsed*/) + { + return event != json::parse_event_t::array_start; + }); + + std::cout << std::boolalpha; + std::cout << "j_invalid.is_discarded() = " << j_invalid.is_discarded() << '\n'; + std::cout << "j_discarded_by_callback = " << j_discarded_by_callback << '\n'; + std::cout << "j_discarded_by_callback.is_discarded() = " << j_discarded_by_callback.is_discarded() << '\n'; +} diff --git a/docs/mkdocs/docs/examples/is_discarded__parse.output b/docs/mkdocs/docs/examples/is_discarded__parse.output new file mode 100644 index 000000000..afb367950 --- /dev/null +++ b/docs/mkdocs/docs/examples/is_discarded__parse.output @@ -0,0 +1,3 @@ +j_invalid.is_discarded() = true +j_discarded_by_callback = null +j_discarded_by_callback.is_discarded() = false diff --git a/docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.cpp b/docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.cpp new file mode 100644 index 000000000..a2354da73 --- /dev/null +++ b/docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.cpp @@ -0,0 +1,32 @@ +#include +#include +#include + +using json = nlohmann::json; + +const char* to_string(const std::strong_ordering& so) +{ + if (std::is_lt(so)) + { + return "less"; + } + else if (std::is_gt(so)) + { + return "greater"; + } + return "equal"; +} + +int main() +{ + // different JSON pointers + json::json_pointer ptr1("/a/b"); + json::json_pointer ptr2("/a/c"); + json::json_pointer ptr3("/a/b/c"); + json::json_pointer ptr4("/a/b"); + + // 3-way compare JSON pointers + std::cout << "\"" << ptr1 << "\" <=> \"" << ptr2 << "\": " << to_string(ptr1 <=> ptr2) << '\n' // *NOPAD* + << "\"" << ptr1 << "\" <=> \"" << ptr3 << "\": " << to_string(ptr1 <=> ptr3) << '\n' // *NOPAD* + << "\"" << ptr1 << "\" <=> \"" << ptr4 << "\": " << to_string(ptr1 <=> ptr4) << std::endl; // *NOPAD* +} diff --git a/docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.output b/docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.output new file mode 100644 index 000000000..083d285d0 --- /dev/null +++ b/docs/mkdocs/docs/examples/json_pointer__operator_spaceship.c++20.output @@ -0,0 +1,3 @@ +"/a/b" <=> "/a/c": less +"/a/b" <=> "/a/b/c": less +"/a/b" <=> "/a/b": equal diff --git a/docs/mkdocs/docs/examples/operator__ValueType.cpp b/docs/mkdocs/docs/examples/operator__ValueType.cpp index e8a1d349d..7ab29ec71 100644 --- a/docs/mkdocs/docs/examples/operator__ValueType.cpp +++ b/docs/mkdocs/docs/examples/operator__ValueType.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include using json = nlohmann::json; @@ -29,7 +29,7 @@ int main() int v5 = json_types["number"]["floating-point"]; std::string v6 = json_types["string"]; std::vector v7 = json_types["array"]; - std::unordered_map v8 = json_types; + std::map v8 = json_types; // print the conversion results std::cout << v1 << '\n'; diff --git a/docs/mkdocs/docs/examples/operator__ValueType.output b/docs/mkdocs/docs/examples/operator__ValueType.output index de471ec02..c6fb1500e 100644 --- a/docs/mkdocs/docs/examples/operator__ValueType.output +++ b/docs/mkdocs/docs/examples/operator__ValueType.output @@ -4,9 +4,9 @@ Hello, world! 1 2 3 4 5 -number: {"floating-point":17.23,"integer":42} -null: null -string: "Hello, world!" -boolean: true array: [1,2,3,4,5] +boolean: true +null: null +number: {"floating-point":17.23,"integer":42} +string: "Hello, world!" [json.exception.type_error.302] type must be boolean, but is string diff --git a/docs/mkdocs/docs/examples/parse_event_t.cpp b/docs/mkdocs/docs/examples/parse_event_t.cpp new file mode 100644 index 000000000..3a56b22a9 --- /dev/null +++ b/docs/mkdocs/docs/examples/parse_event_t.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +using json = nlohmann::json; + +// translate a parse_event_t to a human-readable name +std::string event_name(json::parse_event_t event) +{ + switch (event) + { + case json::parse_event_t::object_start: + return "object_start"; + case json::parse_event_t::object_end: + return "object_end"; + case json::parse_event_t::array_start: + return "array_start"; + case json::parse_event_t::array_end: + return "array_end"; + case json::parse_event_t::key: + return "key"; + case json::parse_event_t::value: + return "value"; + default: + return "unknown"; + } +} + +int main() +{ + // a small JSON text + auto text = R"({"pi": 3.141, "numbers": [1, 2]})"; + + // parse the text and report every event together with its depth; + // returning true keeps every value unchanged + json j = json::parse(text, [](int depth, json::parse_event_t event, json& /*parsed*/) + { + std::cout << depth << " " << event_name(event) << '\n'; + return true; + }); + + // the callback did not change anything, so the parsed value is unaffected + std::cout << j << '\n'; +} diff --git a/docs/mkdocs/docs/examples/parse_event_t.output b/docs/mkdocs/docs/examples/parse_event_t.output new file mode 100644 index 000000000..f900d692f --- /dev/null +++ b/docs/mkdocs/docs/examples/parse_event_t.output @@ -0,0 +1,10 @@ +0 object_start +1 key +1 value +1 key +1 array_start +2 value +2 value +1 array_end +0 object_end +{"numbers":[1,2],"pi":3.141} diff --git a/docs/mkdocs/docs/examples/patch__exception.cpp b/docs/mkdocs/docs/examples/patch__exception.cpp new file mode 100644 index 000000000..9e0a27cab --- /dev/null +++ b/docs/mkdocs/docs/examples/patch__exception.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +using json = nlohmann::json; +using namespace nlohmann::literals; + +int main() +{ + // the original document + json doc = R"( + { + "a": { "b": 1 } + } + )"_json; + + // a patch that tries to move "/a" into one of its own children + json patch = R"( + [ + { "op": "move", "from": "/a", "path": "/a/b" } + ] + )"_json; + + // exception out_of_range.414 + try + { + json patched_doc = doc.patch(patch); + } + catch (const json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + + // the original document is unchanged + std::cout << std::setw(4) << doc << std::endl; +} diff --git a/docs/mkdocs/docs/examples/patch__exception.output b/docs/mkdocs/docs/examples/patch__exception.output new file mode 100644 index 000000000..e6991f5f5 --- /dev/null +++ b/docs/mkdocs/docs/examples/patch__exception.output @@ -0,0 +1,6 @@ +[json.exception.out_of_range.414] cannot move value: 'from' path '/a' is a proper prefix of 'path' '/a/b' +{ + "a": { + "b": 1 + } +} diff --git a/docs/mkdocs/docs/examples/patch_inplace__exception.cpp b/docs/mkdocs/docs/examples/patch_inplace__exception.cpp new file mode 100644 index 000000000..02ebe133a --- /dev/null +++ b/docs/mkdocs/docs/examples/patch_inplace__exception.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +using json = nlohmann::json; +using namespace nlohmann::literals; + +int main() +{ + // the original document + json doc = R"( + { + "a": 1, + "b": 2 + } + )"_json; + + // a patch whose second operation fails + json patch = R"( + [ + { "op": "replace", "path": "/a", "value": 99 }, + { "op": "remove", "path": "/nonexistent" } + ] + )"_json; + + // exception out_of_range.403 + try + { + doc.patch_inplace(patch); + } + catch (const json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } + + // the first operation has already been applied to doc + std::cout << std::setw(4) << doc << std::endl; +} diff --git a/docs/mkdocs/docs/examples/patch_inplace__exception.output b/docs/mkdocs/docs/examples/patch_inplace__exception.output new file mode 100644 index 000000000..34a8c008f --- /dev/null +++ b/docs/mkdocs/docs/examples/patch_inplace__exception.output @@ -0,0 +1,5 @@ +[json.exception.out_of_range.403] key 'nonexistent' not found +{ + "a": 99, + "b": 2 +} diff --git a/docs/mkdocs/docs/examples/sax_no_exception.cpp b/docs/mkdocs/docs/examples/sax_no_exception.cpp new file mode 100644 index 000000000..1eeff466e --- /dev/null +++ b/docs/mkdocs/docs/examples/sax_no_exception.cpp @@ -0,0 +1,40 @@ +#include +#include + +using json = nlohmann::json; + +// a DOM parser that reports parse errors instead of throwing +class sax_no_exception : public nlohmann::detail::json_sax_dom_parser +{ + public: + explicit 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::cout << "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::cout << "parsing unsuccessful!" << std::endl; + } + + std::cout << "parsed value: " << result << std::endl; +} diff --git a/docs/mkdocs/docs/examples/sax_no_exception.output b/docs/mkdocs/docs/examples/sax_no_exception.output new file mode 100644 index 000000000..c2f4b78db --- /dev/null +++ b/docs/mkdocs/docs/examples/sax_no_exception.output @@ -0,0 +1,5 @@ +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] diff --git a/docs/mkdocs/docs/examples/to_bjdata__exception.cpp b/docs/mkdocs/docs/examples/to_bjdata__exception.cpp new file mode 100644 index 000000000..560f3343b --- /dev/null +++ b/docs/mkdocs/docs/examples/to_bjdata__exception.cpp @@ -0,0 +1,20 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a non-empty JSON array + json j = {1, 2, 3}; + + // exception other_error.502 + try + { + json::to_bjdata(j, false, true); + } + catch (const json::other_error& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/to_bjdata__exception.output b/docs/mkdocs/docs/examples/to_bjdata__exception.output new file mode 100644 index 000000000..53c5709fd --- /dev/null +++ b/docs/mkdocs/docs/examples/to_bjdata__exception.output @@ -0,0 +1 @@ +[json.exception.other_error.502] use_type requires use_size = true diff --git a/docs/mkdocs/docs/examples/to_bon8__exception.cpp b/docs/mkdocs/docs/examples/to_bon8__exception.cpp new file mode 100644 index 000000000..48992413b --- /dev/null +++ b/docs/mkdocs/docs/examples/to_bon8__exception.cpp @@ -0,0 +1,22 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a JSON string that is not valid UTF-8 + std::string invalid_utf8; + invalid_utf8.push_back(static_cast(0xFF)); + json j = invalid_utf8; + + // exception type_error.316 + try + { + json::to_bon8(j); + } + catch (const json::type_error& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/to_bon8__exception.output b/docs/mkdocs/docs/examples/to_bon8__exception.output new file mode 100644 index 000000000..22fc8b14b --- /dev/null +++ b/docs/mkdocs/docs/examples/to_bon8__exception.output @@ -0,0 +1 @@ +[json.exception.type_error.316] invalid UTF-8 byte at index 0: 0xFF diff --git a/docs/mkdocs/docs/examples/to_bson__exception.cpp b/docs/mkdocs/docs/examples/to_bson__exception.cpp new file mode 100644 index 000000000..fe12c202f --- /dev/null +++ b/docs/mkdocs/docs/examples/to_bson__exception.cpp @@ -0,0 +1,23 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a JSON object whose key contains a null byte (U+0000) + std::string key = "ab"; + key.push_back('\0'); + key.push_back('c'); + json j = {{key, 1}}; + + // exception out_of_range.409 + try + { + json::to_bson(j); + } + catch (const json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/to_bson__exception.output b/docs/mkdocs/docs/examples/to_bson__exception.output new file mode 100644 index 000000000..c5413f990 --- /dev/null +++ b/docs/mkdocs/docs/examples/to_bson__exception.output @@ -0,0 +1 @@ +[json.exception.out_of_range.409] BSON key cannot contain code point U+0000 (at byte 2) diff --git a/docs/mkdocs/docs/examples/to_msgpack__exception.cpp b/docs/mkdocs/docs/examples/to_msgpack__exception.cpp new file mode 100644 index 000000000..fb20d0ad8 --- /dev/null +++ b/docs/mkdocs/docs/examples/to_msgpack__exception.cpp @@ -0,0 +1,20 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a JSON value with a binary subtype that exceeds 255 + json j = json::binary({1, 2, 3}, 300); + + // exception out_of_range.415 + try + { + json::to_msgpack(j); + } + catch (const json::out_of_range& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/to_msgpack__exception.output b/docs/mkdocs/docs/examples/to_msgpack__exception.output new file mode 100644 index 000000000..c2ea36dba --- /dev/null +++ b/docs/mkdocs/docs/examples/to_msgpack__exception.output @@ -0,0 +1 @@ +[json.exception.out_of_range.415] subtype 300 is too large for the MessagePack ext type (max 255) diff --git a/docs/mkdocs/docs/examples/to_ubjson__exception.cpp b/docs/mkdocs/docs/examples/to_ubjson__exception.cpp new file mode 100644 index 000000000..8fe481d84 --- /dev/null +++ b/docs/mkdocs/docs/examples/to_ubjson__exception.cpp @@ -0,0 +1,20 @@ +#include +#include + +using json = nlohmann::json; + +int main() +{ + // create a non-empty JSON array + json j = {1, 2, 3}; + + // exception other_error.502 + try + { + json::to_ubjson(j, false, true); + } + catch (const json::other_error& e) + { + std::cout << e.what() << '\n'; + } +} diff --git a/docs/mkdocs/docs/examples/to_ubjson__exception.output b/docs/mkdocs/docs/examples/to_ubjson__exception.output new file mode 100644 index 000000000..53c5709fd --- /dev/null +++ b/docs/mkdocs/docs/examples/to_ubjson__exception.output @@ -0,0 +1 @@ +[json.exception.other_error.502] use_type requires use_size = true diff --git a/docs/mkdocs/docs/examples/value__exception.cpp b/docs/mkdocs/docs/examples/value__exception.cpp new file mode 100644 index 000000000..1d611d4c9 --- /dev/null +++ b/docs/mkdocs/docs/examples/value__exception.cpp @@ -0,0 +1,33 @@ +#include +#include + +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 a0c84edaf..23a21e7d4 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..ff5d6d8a7 100644 --- a/docs/mkdocs/docs/features/binary_formats/bon8.md +++ b/docs/mkdocs/docs/features/binary_formats/bon8.md @@ -92,7 +92,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" @@ -146,7 +146,7 @@ Non-negative integers are read as number_unsigned, negative integers as number_i 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 33403a58c..aaf1253a7 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). - [Comments](comments.md) and [trailing commas](trailing_commas.md) — opt-in relaxations of the JSON grammar. ## Accessing and modifying values @@ -43,7 +44,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()`. ![Illustration from cppreference.com](../images/range-begin-end.svg) @@ -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. ![Illustration from cppreference.com](../images/range-rbegin-rend.svg) -??? 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 2bc8a4a5b..471ca160a 100644 --- a/docs/mkdocs/docs/features/macros.md +++ b/docs/mkdocs/docs/features/macros.md @@ -163,7 +163,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/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..aef00ac2c 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" @@ -129,7 +130,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 +155,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 cf37b044a..1087c049d 100644 --- a/docs/mkdocs/docs/features/types/number_handling.md +++ b/docs/mkdocs/docs/features/types/number_handling.md @@ -67,14 +67,29 @@ 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`. - The number types can be changed, see [Template number types](#template-number-types). - - As of version 3.9.1, the conversion is realized by + - Integers are converted by the library's own digit parser. Floating-point numbers are converted with + [`std::from_chars`](https://en.cppreference.com/w/cpp/utility/from_chars) if the library is compiled with C++17 + and the standard library supports it, then with an exact fast path for `#!c double` values with few significant + digits, and otherwise with the locale-aware + [`std::strtod`](https://en.cppreference.com/w/cpp/string/byte/strtof) (`std::strtof`/`std::strtold` for the + other floating-point types). 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`](https://en.cppreference.com/w/cpp/string/byte/strtof), respectively. + [`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 8ed23e156..e6bfd1ca8 100644 --- a/docs/mkdocs/docs/features/types/template_parameters.md +++ b/docs/mkdocs/docs/features/types/template_parameters.md @@ -26,8 +26,9 @@ Requirements are split into two groups: diagnosed with dedicated error messages, and violating most of them results in a compiler error somewhere inside the library. Four violations are not caught at compile time at all: - - A [`StringType`](#stringtype) whose `data()` is not null-terminated compiles and silently misparses numbers, - because the lexer hands the buffer to `#!cpp std::strtoull`/`#!cpp std::strtoll`/`#!cpp std::strtod`. + - A [`StringType`](#stringtype) whose `data()` is not null-terminated compiles and can silently misparse + floating-point numbers, because the lexer may hand the buffer to `#!cpp std::strtod`, which reads up to the + terminating null character. - A stateful [`AllocatorType`](#allocatortype) compiles and silently ignores its state: allocation, deallocation, and [`get_allocator()`](../../api/basic_json/get_allocator.md) each use a different default-constructed instance. - The two [cross-specialization conversions](#cross-specialization-conversions) below. These abort on an assertion @@ -213,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" @@ -306,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" @@ -348,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+=`, @@ -447,7 +448,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" @@ -534,8 +535,9 @@ therefore silently changes parse results rather than raising an error. See `NumberFloatType` must be one of `#!cpp float`, `#!cpp double`, or `#!cpp long double`: -- The [parser](../parsing/index.md) converts number literals with `#!cpp std::strtof`, `#!cpp std::strtod`, or - `#!cpp std::strtold`; the library provides overloads for exactly these three types. +- The [parser](../parsing/index.md) converts number literals with `#!cpp std::from_chars` or, as a fallback, with + `#!cpp std::strtof`, `#!cpp std::strtod`, or `#!cpp std::strtold`; the library provides overloads for exactly these + three types. - [`dump`](../../api/basic_json/dump.md) falls back to `#!cpp std::snprintf` with the `%g` and `%Lg` conversion specifiers, for which the library likewise provides only `#!cpp double` and `#!cpp long double` overloads (`#!cpp float` is promoted to `#!cpp double`). @@ -668,7 +670,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..fffe3fd43 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) +[![logos of customers using the library](../images/customers.png)](../images/customers.png) ## Space Exploration @@ -54,7 +54,7 @@ the result of an internet search. If you know further customers of the library, - [**Madden NFL 25**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a sports simulation game capturing the excitement of American football with realistic gameplay and team management features - [**Madden NFL 26**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), an American football simulation with franchise and team management modes - [**Madden NFL 27**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), the latest installment of the American football simulation series -- [**Marne**](https://marne.io/licenses), an unofficial private server platform for hosting custom Battlefield 1 game experiences +- **Marne**, an unofficial private server platform for hosting custom Battlefield 1 game experiences - [**Minecraft**](https://www.minecraft.net/zh-hant/attribution), a popular sandbox video game - [**Mumble**](https://github.com/mumble-voip/mumble), a low-latency, open-source voice chat application widely used by gaming communities - [**NHL 22**](https://www.mobygames.com/person/1195889/niels-lohmann/credits/), a hockey simulation game offering realistic gameplay, team management, and various modes to enhance the hockey experience @@ -80,14 +80,14 @@ the result of an internet search. If you know further customers of the library, - [**Audinate**](https://www.audinate.com/legal/software-licensing/dante-av-h-open-source-licenses/), a provider of networked audio solutions specializing in Dante technology, which facilitates high-quality digital audio transport over IP networks - [**Canon CanoScan LIDE**](https://carolburo.com/wp-content/uploads/2024/06/LiDE400_OnlineManual_Win_FR_V02.pdf), a series of flatbed scanners offering high-resolution image scanning for home and office use - [**Canon PIXMA Printers**](https://www.mediaexpert.pl/products/files/73/7338196/Instrukcja-obslugi-CANON-Pixma-TS7450i.pdf), a line of all-in-one inkjet printers known for high-quality printing and wireless connectivity -- [**Cisco Webex Desk Camera**](https://www.cisco.com/c/dam/en_us/about/doing_business/open_source/docs/CiscoWebexDeskCamera-23-1622100417.pdf), a video camera designed for professional-quality video conferencing and remote collaboration +- **Cisco Webex Desk Camera**, a video camera designed for professional-quality video conferencing and remote collaboration - [**DJI Edge SDK**](https://github.com/dji-sdk/Edge-SDK-V2-Demo), the reference applications for DJI's Edge SDK, used to build edge computing services on DJI drone docks - [**Elgato Stream Deck**](https://github.com/elgatosf/streamdeck-obs-plugin2), a family of programmable control surfaces for content creators and their plugin ecosystem - [**Instagrid**](https://instagrid.co/intellectual-property/foss), a manufacturer of portable, high-performance battery systems for professional mobile power supply - [**iRobot**](https://iot-content.irobot.com/iw/sfsites/c/cms/delivery/media/MCKRLTPDJSSJBNJKDA5SG5UVVIIQ), a manufacturer of autonomous home robots including the Roomba vacuum cleaner range - [**Logitech Logi Bolt**](https://opensource.logitech.com/wiki/Logi_BoltApp/), the management application for Logitech's secure wireless connectivity technology - [**Novitus**](https://novitus.pl/licencjepensource), a manufacturer of fiscal cash registers and point-of-sale devices -- [**Philips Hue Personal Wireless Lighting**](http://2ak5ape.257.cz/), a smart lighting system for customizable and wireless home illumination +- **Philips Hue Personal Wireless Lighting**, a smart lighting system for customizable and wireless home illumination - [**Ray-Ban Meta Smart glasses**](https://www.meta.com/de/en/legal/smart-glasses/third-party-notices-android/03/), a pair of smart glasses designed for capturing photos and videos with integrated connectivity and social features - [**Razer Synapse**](https://mysupport.razer.com/app/answers/detail/a_id/14146/~/open-source-software-for-razer-software), a unified configuration software enabling hardware customization for Razer devices - [**Sharp Professional Displays**](https://jp.sharp/restricted/business/lcd-display/cms/images/source_pnla862/PN-LA652_752_862_LicenseInformation.pdf), a range of large-format interactive displays for business and education @@ -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**, 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 407f3c3f1..c78aeaa68 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. @@ -1009,7 +1009,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 597c69496..62956ceb4 100644 --- a/docs/mkdocs/docs/home/license.md +++ b/docs/mkdocs/docs/home/license.md @@ -1,6 +1,6 @@ # License - +OSI approved 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..7de1d2c0d 100644 --- a/docs/mkdocs/docs/index.md +++ b/docs/mkdocs/docs/index.md @@ -1,3 +1,112 @@ # JSON for Modern C++ -![](images/json.gif) +![JSON for Modern C++](images/json.gif) + +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 a single header, `json.hpp`, with no dependencies, no subproject, and no +complex build system to set up. 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 71512cbd5..4353e739d 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 @@ -176,15 +177,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` @@ -203,6 +211,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 2bbaa8604..ad89e4fba 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 cc975b98bc7bc8e77468e8ee888a972de772418a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19422 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∈`gy(ms)zid=_*Hti#KmRgg*aY0PdA%gZIsB6NZ9?Af1#6Zznh^ z?|-b2|NOOY%AB7(Ng5Yd-Huoq?V@Z#+oFkeXNj=Em2oNqF*Vi4Y+9X?SXoH&Uhk4S{mp{{sT4*#&0swLsU_)|#Dq^#{^8 z)R2-B5?X;7lBoQ4x|awC0=}&S=@}hCcqtN4p2<#8kQqC{rUPj~^E$^Vj3WwMv7ZF4 zy(*MKCR?k72rWxb1*Wns=6!+$j^ZCUz0$C7u6wsjwAVq^TzG>_OLP+KHWL~%H#Q;e|Kq2w9=#Rs_5pKY>Trr$L z`8SXI=QCRb*yW_(%75g-aqfWc(f>iK_L3n0?}ej*F2c}O{%5x?fw8M&f*+Pm zo+UJ|6Vzh_KmmiH%}Eh4Sm1SV9-50GLh($&wvz{;UyU~b7U(~{zex%quQ+WK_i1Rl zmD{o{0QzMXLI0L7JRh=^B>-+7YgtJwZA%tKGnxryeuEo4$Ijbie8)4!ee?$2b|`LNR&VZ93ER&leE{fCirX?0!bu<9KL4VrI_mo8q(}D zS(8RM3F4`OpOM9f&gYC44k7Po70JrX7SmIWRJQX(1T6o{&~7zme20wfdgp!ZyzSE_ zVX8XNL`T1~zw!yMqUY1pJVpPFeDm~xC{DzsD2com4JT{d1XYZVDVF_r=u3y|VT^5m zF_~3Y&i+Z0Na5p@YB zTH`}HSB537i>ZDkJq-mT;XK8+$O;#@yBIsOm>=%Qv;z8?iOd~{a-o0y>e#{+znoA= z2Y+SQV_=-p87|JY<1DiFvL=fn)o*|eSk8DLXaFp;;&ormzWWc2gFKiERh~h4W^w(6 zfcopkHpSKmOp#BP_I|H9RfNnxNR}#-F|IIEH*IQt;+klb*+g-Yh7@Zlp=*AP(}!GC zb=7|*rKJ8g|LXesI_8$q<Dsdm( z;I+@dKjU*7&r34Lz-BVfgl7ID^A$% z;2U|r>M}QI@AITkkjB000I-OM6$D7@{Cl<}T~Q#hBSYLZ5bV=j)y6po4#7 zq522OZZ%xqh6DG|dP!dq;cE2+jLlbJH@7`7wCROavdY&j|A*Ka3~aN{H=ZDO$iMRN z1T3Jj*1x9w5j}pJVP+C|74-T(^SvRVe^{IjrcHZYJyx57lE%-+#T^td`+^S+YzEo; z_@%Y_=r^=zVfRY9c0ZT$OTKW-yKKNWz!gxBLi{DZ?P5#4WVSh!z&)f6!}&FcwX->V z3jfgv2|UA!ymUM2jNx|w)M^p@ru28DLb%>a_)V)(H&feUe>JH3%+G4bz14u5+e4d(MKt&q(BhsI@wS?F~p z-7B-I;6-~t?<^v)--jaECn7QHa6lYW9|m6LKE4H04o^x>oLutx*bx9Y-Zf=6|g51HeU0BF@*=DT_vcw%Cj^R)c7-wEF@Nzx+T5 zo~<-0yak?rNnkXaiqS8BB@c0n5ymTd@w?|+%}7DGbIT$jN{Lb3bydHHtT)da;!64q zgm788u1B;08{x*c8P-31`K_?0jq*2Ek~m*r3N#hjpd`pGZ?mAswEJ7ZC9zy`=FnzPE=Zd)YmC>JBVFrA<|IZOYpNChv2M9s{5VjBm+Q43|X&f(J{NpE( aufd>S8@@=`0RL~-8xa9X{t{m8@Bar_#?$Zs 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 eb2a520a8f27bd5e84b03466cd1d79c329203286..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30826 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 Zc9O8;;I^_u@I8bfWF!>DD?|-H{Xb<1g}49! 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 74657f264d65d6a2e8f6602665452122f1029a08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55236 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 diff --git a/docs/mkdocs/docs/integration/package_managers.md b/docs/mkdocs/docs/integration/package_managers.md index 792a0fa5a..2fbb0aad2 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) - - [![Homebrew package](https://repology.org/badge/version-for-repo/homebrew/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - [![Homebrew package](https://img.shields.io/homebrew/v/nlohmann-json)](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) - - [![ConanCenter package](https://repology.org/badge/version-for-repo/conancenter/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - [![ConanCenter package](https://img.shields.io/conan/v/nlohmann_json)](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) - - [![Spack package](https://repology.org/badge/version-for-repo/spack/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - [![Spack package](https://img.shields.io/spack/v/nlohmann-json)](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) - - [![Vcpkg package](https://repology.org/badge/version-for-repo/vcpkg/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - [![vcpkg package](https://img.shields.io/vcpkg/v/nlohmann-json)](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" - ![](nuget/nuget-search-package.png) + 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. + ![Right-clicking a project in Solution Explorer and selecting "Manage NuGet Packages…"](nuget/nuget-search-package.png) - ![](nuget/nuget-select-package.png) + 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 + ![Searching for and selecting the nlohmann.json package in the NuGet package manager](nuget/nuget-select-package.png) - 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: - - ![](nuget/nuget-project-changes.png) - - 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`: - - ![](nuget/nuget-package-content.png) - - !!! 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. - - ![](nuget/nuget-project-makefile.png) - - 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://img.shields.io/conda/v/conda-forge/nlohmann_json) + - [![Conda package](https://img.shields.io/conda/v/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" -[![MSYS2 clang64 package](https://repology.org/badge/version-for-repo/msys2_clang64/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) -[![MSYS2 clangarm64 package](https://repology.org/badge/version-for-repo/msys2_clangarm64/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) -[![MSYS2 mingw package](https://repology.org/badge/version-for-repo/msys2_mingw/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) -[![MSYS2 ucrt64 package](https://repology.org/badge/version-for-repo/msys2_ucrt64/nlohmann-json.svg)](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. + - [![MSYS2 package](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpackages.msys2.org%2Fapi%2Fsearch%3Fquery%3Dnlohmann-json%26qtype%3Dpkg&query=%24.results.exact.version&label=msys2&prefix=v)](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/) - - [![MacPorts package](https://repology.org/badge/version-for-repo/macports/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) + - [![MacPorts package](https://img.shields.io/macports/v/nlohmann-json)](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: [![Packaging status](https://repology.org/badge/tiny-repos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) - -??? example "Package version overview" - - [![Packaging status](https://repology.org/badge/vertical-allrepos/nlohmann-json.svg)](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. + +[![CocoaPods package](https://img.shields.io/cocoapods/v/nlohmann_json)](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. - -![](https://img.shields.io/cocoapods/v/nlohmann_json) - -!!! 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 70537bd27..1d79969b3 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 @@ -233,6 +235,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: @@ -249,6 +253,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 @@ -287,7 +292,7 @@ nav: - 'JSON_DIAGNOSTICS': api/macros/json_diagnostics.md - 'JSON_DIAGNOSTIC_POSITIONS': api/macros/json_diagnostic_positions.md - 'JSON_DISABLE_ENUM_SERIALIZATION': api/macros/json_disable_enum_serialization.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 @@ -379,8 +384,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: @@ -388,7 +406,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 @@ -399,9 +418,18 @@ 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: ['https://repology.org/*'] # connection errors; repology.org is suspended since 2026-09 + 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 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 c8d637d06..a3d405a88 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..0559499d6 --- /dev/null +++ b/docs/mkdocs/scripts/check_version_history.py @@ -0,0 +1,102 @@ +#!/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 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) + + +def header(tag, cache={}): + if tag not in cache: + cache[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: + cache[tag] = result.stdout + break + return cache[tag] + + +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/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 5fec57a70..0001c61f5 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -54,7 +54,8 @@ using parser_callback_t = /*! @brief syntax analysis -This class implements a recursive descent parser. +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. */ template class parser diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 1540a8d6f..a74e6a9cb 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -77,7 +77,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 { @@ -86,7 +86,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(); @@ -1092,7 +1092,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 3a4eb79f4..e6e0ad06a 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -305,7 +305,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/json.hpp b/include/nlohmann/json.hpp index 500fcddf2..437da15cf 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -4863,7 +4863,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 @@ -4882,7 +4882,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, @@ -5035,7 +5035,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } #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, @@ -5047,7 +5047,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) { parser(detail::input_adapter(i)).parse(false, j); @@ -6429,7 +6429,7 @@ inline namespace json_literals { /// @brief user-defined string literal for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ +/// @sa https://json.nlohmann.me/api/operator_literal_json/ JSON_HEDLEY_NON_NULL(1) #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) inline nlohmann::json operator""_json(const char* s, std::size_t n) @@ -6451,7 +6451,7 @@ inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) #endif /// @brief user-defined string literal for JSON pointer -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ +/// @sa https://json.nlohmann.me/api/operator_literal_json_pointer/ JSON_HEDLEY_NON_NULL(1) #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 576498738..2fa70b4d8 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2716,7 +2716,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 \ @@ -17186,7 +17186,8 @@ using parser_callback_t = /*! @brief syntax analysis -This class implements a recursive descent parser. +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. */ template class parser @@ -18919,7 +18920,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 { @@ -18928,7 +18929,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(); @@ -19934,7 +19935,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, @@ -30944,7 +30946,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 @@ -30963,7 +30965,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, @@ -31116,7 +31118,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } #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, @@ -31128,7 +31130,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) { parser(detail::input_adapter(i)).parse(false, j); @@ -32510,7 +32512,7 @@ inline namespace json_literals { /// @brief user-defined string literal for JSON values -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/ +/// @sa https://json.nlohmann.me/api/operator_literal_json/ JSON_HEDLEY_NON_NULL(1) #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) inline nlohmann::json operator""_json(const char* s, std::size_t n) @@ -32532,7 +32534,7 @@ inline nlohmann::json operator""_json(const char8_t* s, std::size_t n) #endif /// @brief user-defined string literal for JSON pointer -/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/ +/// @sa https://json.nlohmann.me/api/operator_literal_json_pointer/ JSON_HEDLEY_NON_NULL(1) #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) inline nlohmann::json::json_pointer operator""_json_pointer(const char* s, std::size_t n)