Squashed 'external/json/' changes from 60c48755e..55f93686c

55f93686c Merge branch 'release/3.12.0'
34e46d76d 🔖 set version to 3.12.0
00ecc7ed7 ⬆️ Bump github/codeql-action from 3.28.13 to 3.28.14 (#4726)
4424a0fcc 📝 update documentation (#4723)
11aa5f944 Make std::filesystem::path conversion to/from UTF-8 encoded string explicit (#4631)
79587f896 ⬆️ Bump mkdocs-material from 9.6.10 to 9.6.11 in /docs/mkdocs (#4715)
b67f8644e ⬆️ Bump actions/dependency-review-action from 4.5.0 to 4.6.0 (#4716)
71884486d ⬆️ Bump step-security/harden-runner from 2.11.0 to 2.11.1 (#4718)
9ef496738 ⬆️ Bump cpplint from 2.0.0 to 2.0.1 in /cmake/requirements (#4719)
9f40a7b45 ⬆️ Bump mkdocs-material from 9.6.9 to 9.6.10 in /docs/mkdocs (#4711)
d41ca94fa Adjust CMake minimal version (#4709)
3a5703931 ⬆️ Bump cppcheck from 1.4.8 to 1.5.0 in /cmake/requirements (#4698)
4d216e0c3 ⬆️ Bump actions/upload-artifact from 4.6.1 to 4.6.2 (#4700)
f971dd770 ⬆️ Bump github/codeql-action from 3.28.11 to 3.28.13 (#4707)
cd92c09c1 tests: Fix ignored attributes warning during build (#4670)
b477d2b95 Suppress clang-analyzer-webkit.NoUncountedMemberChecker (#4701)
11a835df8 ⬆️ Bump cppcheck from 1.4.7 to 1.4.8 in /cmake/requirements (#4697)
b592b6f2d ⬆️ Bump mkdocs-material from 9.6.8 to 9.6.9 in /docs/mkdocs (#4695)
e2c95baef ⬆️ Bump mkdocs-git-revision-date-localized-plugin (#4689)
7abcb5e9a fixes issue 4691 (#4693)
5474b2227 ⬆️ Bump mkdocs-material from 9.6.5 to 9.6.8 in /docs/mkdocs (#4688)
6e684350b ⬆️ Bump github/codeql-action from 3.28.10 to 3.28.11 (#4683)
f506d8acc ⬆️ Bump jinja2 from 3.1.5 to 3.1.6 in /tools/generate_natvis (#4680)
34665ae64 Correct typo in sax_interface.md (#4679)
f3dc4684b ⬆️ Bump github/codeql-action from 3.28.9 to 3.28.10 (#4661)
0b938993e ⬆️ Bump lukka/get-cmake from 3.31.5 to 3.31.6 (#4668)
543d8e417 ⬆️ Bump actions/upload-artifact from 4.6.0 to 4.6.1 (#4665)
f2e494686 ⬆️ Bump ossf/scorecard-action from 2.4.0 to 2.4.1 (#4664)
8215dbafb ⬆️ Bump mkdocs-material from 9.6.4 to 9.6.5 in /docs/mkdocs (#4659)
a3143f5f2 ⬆️ Bump step-security/harden-runner from 2.10.4 to 2.11.0 (#4652)
0b6881a95 Add regression test for #3810 (#4608)
a43350c4e Remove wsjcpp package manager (#4623)
8fb5d6f92 Some documentation updates (#4636)
2dc82053d ⬆️ Bump mkdocs-material from 9.5.50 to 9.6.4 in /docs/mkdocs (#4648)
bf6b1e2f4 ⬆️ Bump github/codeql-action from 3.28.6 to 3.28.9 (#4646)
606b6347e ⬆️ Bump coverallsapp/github-action from 2.3.4 to 2.3.6 (#4634)
c7d949f9f ⬆️ Bump github/codeql-action from 3.28.4 to 3.28.6 (#4635)
e90c860d5 Add note on derived return type for value function (#4628)
d0789e365 Bump lukka/get-cmake from 3.31.4 to 3.31.5 (#4625)
97dd60c22 Bump github/codeql-action from 3.28.3 to 3.28.4 (#4624)
666d06144 Bump github/codeql-action from 3.28.2 to 3.28.3 (#4620)
bf8ccc20e fix compilation issue (#4613)
786c5040e Bump github/codeql-action from 3.28.1 to 3.28.2 (#4617)
bd4fea39e Bump actions/stale from 9.0.0 to 9.1.0 (#4616)
8c7dcd3b4 Bump step-security/harden-runner from 2.10.3 to 2.10.4 (#4614)
b23cdeac2 Bump mkdocs-material from 9.5.49 to 9.5.50 in /docs/mkdocs (#4615)
1b813519c Add VisionOS support to Swift Package Manager Package.swift definition file (#4611)
f06604fce Bump the copyright years (#4606)
d23291ba2 use diagnostic positions in exceptions (#4585)
0f9e6ae09 Fix broken links (#4605)
8a882f32e Generate template functions with NLOHMANN_DEFINE_TYPE macros (#4597)
bdb8d2b7b Serialize empty tuple into '[]'  instead of null (#4594)
e72046ef9 Bump step-security/harden-runner from 2.10.2 to 2.10.3 (#4604)
4a0081a1c Bump actions/upload-artifact from 4.5.0 to 4.6.0 (#4603)
52b261421 Bump srvaroa/labeler (#4602)
f74e5c6a5 Bump github/codeql-action from 3.27.9 to 3.28.1 (#4601)
e25a82461 Bump lukka/get-cmake from 3.31.2 to 3.31.4 (#4600)
26cfec34b Clean up and document project files (#4560)
ad2ee1853 Fix coverage job (#4595)
2d42229f4 Support BSON uint64 de/serialization (#4590)
1809b3d80 Add note to Jetbrains support (#4592)
48e7b4c23 BJData Fixes (#4588)
0cb1241d5 Improve Bazel support: Switch to Bzlmod (#4584)
2e50d5b2f BJData optimized binary array type (#4513)

git-subtree-dir: external/json
git-subtree-split: 55f93686c01528224f448c19128836e7df245f72
This commit is contained in:
irisz64
2025-06-26 22:22:03 +02:00
parent a28dbbf733
commit 55f3024dc9
787 changed files with 5713 additions and 2879 deletions

View File

@@ -5,47 +5,49 @@ import os.path
import re
import sys
import yaml
warnings = 0
def report(rule, location, description):
def report(rule, location, description) -> None:
global warnings
warnings += 1
print(f'{warnings:3}. {location}: {description} [{rule}]')
def check_structure():
def check_structure() -> None:
expected_sections = [
'Template parameters',
'Specializations',
'Iterator invalidation',
'Requirements',
'Member types',
'Member functions',
'Member variables',
'Static functions',
'Non-member functions',
'Literals',
'Helper classes',
'Parameters',
'Return value',
'Exception safety',
'Exceptions',
'Complexity',
'Possible implementation',
'Default definition',
'Notes',
'Examples',
'See also',
'Version history'
"Template parameters",
"Specializations",
"Iterator invalidation",
"Requirements",
"Member types",
"Member functions",
"Member variables",
"Static functions",
"Non-member functions",
"Literals",
"Helper classes",
"Parameters",
"Return value",
"Exception safety",
"Exceptions",
"Complexity",
"Possible implementation",
"Default definition",
"Notes",
"Examples",
"See also",
"Version history",
]
required_sections = [
'Examples',
'Version history'
"Examples",
"Version history",
]
files = sorted(glob.glob('api/**/*.md', recursive=True))
files = sorted(glob.glob("api/**/*.md", recursive=True))
for file in files:
with open(file) as file_content:
section_idx = -1 # the index of the current h2 section
@@ -60,30 +62,30 @@ def check_structure():
for lineno, original_line in enumerate(file_content.readlines()):
line = original_line.strip()
if line.startswith('# '):
if line.startswith("# "):
h1sections += 1
# there should only be one top-level title
if h1sections > 1:
report('structure/unexpected_section', f'{file}:{lineno+1}', f'unexpected top-level title "{line}"')
report("structure/unexpected_section", f"{file}:{lineno+1}", f'unexpected top-level title "{line}"')
h1sections = 1
# Overview pages should have a better title
if line == '# Overview':
report('style/title', f'{file}:{lineno+1}', 'overview pages should have a better title than "Overview"')
if line == "# Overview":
report("style/title", f"{file}:{lineno+1}", 'overview pages should have a better title than "Overview"')
# lines longer than 160 characters are bad (unless they are tables)
if len(line) > 160 and '|' not in line:
report('whitespace/line_length', f'{file}:{lineno+1} ({current_section})', f'line is too long ({len(line)} vs. 160 chars)')
if len(line) > 160 and "|" not in line:
report("whitespace/line_length", f"{file}:{lineno+1} ({current_section})", f"line is too long ({len(line)} vs. 160 chars)")
# sections in `<!-- NOLINT -->` comments are treated as present
if line.startswith('<!-- NOLINT'):
current_section = line.strip('<!-- NOLINT')
current_section = current_section.strip(' -->')
if line.startswith("<!-- NOLINT"):
current_section = line.strip("<!-- NOLINT")
current_section = current_section.strip(" -->")
existing_sections.append(current_section)
# check if sections are correct
if line.startswith('## '):
if line.startswith("## "):
# before starting a new section, check if the previous one documented all overloads
if current_section in documented_overloads and last_overload != 0:
if len(documented_overloads[current_section]) > 0 and len(documented_overloads[current_section]) != last_overload:
@@ -91,21 +93,20 @@ def check_structure():
undocumented = [x for x in expected if x not in documented_overloads[current_section]]
unexpected = [x for x in documented_overloads[current_section] if x not in expected]
if len(undocumented):
report('style/numbering', f'{file}:{lineno} ({current_section})', f'undocumented overloads: {", ".join([f"({x})" for x in undocumented])}')
report("style/numbering", f"{file}:{lineno} ({current_section})", f'undocumented overloads: {", ".join([f"({x})" for x in undocumented])}')
if len(unexpected):
report('style/numbering', f'{file}:{lineno} ({current_section})', f'unexpected overloads: {", ".join([f"({x})" for x in unexpected])}')
report("style/numbering", f"{file}:{lineno} ({current_section})", f'unexpected overloads: {", ".join([f"({x})" for x in unexpected])}')
current_section = line.strip('## ')
current_section = line.strip("## ")
existing_sections.append(current_section)
if current_section in expected_sections:
idx = expected_sections.index(current_section)
if idx <= section_idx:
report('structure/section_order', f'{file}:{lineno+1}', f'section "{current_section}" is in an unexpected order (should be before "{expected_sections[section_idx]}")')
report("structure/section_order", f"{file}:{lineno+1}", f'section "{current_section}" is in an unexpected order (should be before "{expected_sections[section_idx]}")')
section_idx = idx
else:
if 'index.md' not in file: # index.md files may have a different structure
report('structure/unknown_section', f'{file}:{lineno+1}', f'section "{current_section}" is not part of the expected sections')
elif "index.md" not in file: # index.md files may have a different structure
report("structure/unknown_section", f"{file}:{lineno+1}", f'section "{current_section}" is not part of the expected sections')
# collect the numbered items of the current section to later check if they match the number of overloads
if last_overload != 0 and not in_initial_code_example:
@@ -116,64 +117,106 @@ def check_structure():
documented_overloads[current_section].append(number)
# code example
if line == '```cpp' and section_idx == -1:
if line == "```cpp" and section_idx == -1:
in_initial_code_example = True
if in_initial_code_example and line.startswith('//') and line not in ['// since C++20', '// until C++20']:
if in_initial_code_example and line.startswith("//") and line not in ["// since C++20", "// until C++20"]:
# check numbering of overloads
if any(map(str.isdigit, line)):
number = int(re.findall(r'\d+', line)[0])
number = int(re.findall(r"\d+", line)[0])
if number != last_overload + 1:
report('style/numbering', f'{file}:{lineno+1}', f'expected number ({number}) to be ({last_overload +1 })')
report("style/numbering", f"{file}:{lineno+1}", f"expected number ({number}) to be ({last_overload +1 })")
last_overload = number
if any(map(str.isdigit, line)) and '(' not in line:
report('style/numbering', f'{file}:{lineno+1}', f'number should be in parentheses: {line}')
if any(map(str.isdigit, line)) and "(" not in line:
report("style/numbering", f"{file}:{lineno+1}", f"number should be in parentheses: {line}")
if line == '```' and in_initial_code_example:
if line == "```" and in_initial_code_example:
in_initial_code_example = False
# consecutive blank lines are bad
if line == '' and previous_line == '':
report('whitespace/blank_lines', f'{file}:{lineno}-{lineno+1} ({current_section})', 'consecutive blank lines')
if line == "" and previous_line == "":
report("whitespace/blank_lines", f"{file}:{lineno}-{lineno+1} ({current_section})", "consecutive blank lines")
# check that non-example admonitions have titles
untitled_admonition = re.match(r'^(\?\?\?|!!!) ([^ ]+)$', line)
if untitled_admonition and untitled_admonition.group(2) != 'example':
report('style/admonition_title', f'{file}:{lineno} ({current_section})', f'"{untitled_admonition.group(2)}" admonitions should have a title')
untitled_admonition = re.match(r"^(\?\?\?|!!!) ([^ ]+)$", line)
if untitled_admonition and untitled_admonition.group(2) != "example":
report("style/admonition_title", f"{file}:{lineno} ({current_section})", f'"{untitled_admonition.group(2)}" admonitions should have a title')
previous_line = line
if 'index.md' not in file: # index.md files may have a different structure
if "index.md" not in file: # index.md files may have a different structure
for required_section in required_sections:
if required_section not in existing_sections:
report('structure/missing_section', f'{file}:{lineno+1}', f'required section "{required_section}" was not found')
report("structure/missing_section", f"{file}:{lineno+1}", f'required section "{required_section}" was not found')
def check_examples():
example_files = sorted(glob.glob('../../examples/*.cpp'))
markdown_files = sorted(glob.glob('**/*.md', recursive=True))
def check_examples() -> None:
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
for example_file in example_files:
example_file = os.path.join('examples', os.path.basename(example_file))
example_file = os.path.join("examples", os.path.basename(example_file))
found = False
for markdown_file in markdown_files:
content = ' '.join(open(markdown_file).readlines())
content = " ".join(open(markdown_file).readlines())
if example_file in content:
found = True
break
if not found:
report('examples/missing', f'{example_file}', 'example file is not used in any documentation file')
report("examples/missing", f"{example_file}", "example file is not used in any documentation file")
if __name__ == '__main__':
print(120 * '-')
def check_links() -> None:
"""Check that every entry in the navigation (nav in mkdocs.yml) links to at most one file. If a file is linked more
than once, then the first entry is repeated. See https://github.com/nlohmann/json/issues/4564 for the issue in
this project and https://github.com/mkdocs/mkdocs/issues/3428 for the root cause.
The issue can be fixed by merging the keys, so
- 'NLOHMANN_JSON_VERSION_MAJOR': api/macros/nlohmann_json_version_major.md
- 'NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md
would be replaced with
- 'NLOHMANN_JSON_VERSION_MAJOR, NLOHMANN_JSON_VERSION_MINOR': api/macros/nlohmann_json_version_major.md
"""
file_with_path = {}
def collect_links(node, path="") -> None:
if isinstance(node, list):
for x in node:
collect_links(x, path)
elif isinstance(node, dict):
for p, x in node.items():
collect_links(x, path + "/" + p)
else:
if node not in file_with_path:
file_with_path[node] = []
file_with_path[node].append(path)
with open("../mkdocs.yml") as mkdocs_file:
# see https://github.com/yaml/pyyaml/issues/86#issuecomment-1042485535
yaml.add_multi_constructor("tag:yaml.org,2002:python/name", lambda loader, suffix, node: None, Loader=yaml.SafeLoader)
yaml.add_multi_constructor("!ENV", lambda loader, suffix, node: None, Loader=yaml.SafeLoader)
y = yaml.safe_load(mkdocs_file)
collect_links(y["nav"])
for duplicate_file in [x for x in file_with_path if len(file_with_path[x]) > 1]:
file_list = [f'"{x}"' for x in file_with_path[duplicate_file]]
file_list_str = ", ".join(file_list)
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')
if __name__ == "__main__":
print(120 * "-")
check_structure()
check_examples()
print(120 * '-')
check_links()
print(120 * "-")
if warnings > 0:
sys.exit(1)