Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
document.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "document.h"
5
7
8#include <QJsonArray>
9
11
12using namespace Qt::Literals::StringLiterals;
13
14namespace IR {
15
16/*!
17 \struct IR::Document
18 \brief Intermediate representation for a documentation topic.
19
20 Document contains all information needed to render a single documentation
21 page using templates. All links are pre-resolved, sections are pre-organized,
22 and file paths are pre-computed. The template engine receives only this IR
23 and performs no lookups or resolution itself.
24
25 The struct includes classification metadata (nodeType, genus, status, access)
26 that allows templates to conditionally render content based on the type and
27 visibility of the documented entity.
28*/
29
30/*!
31 Converts the QmlTypeInfo to a QJsonObject for template rendering.
32
33 Always emits \c isSingleton and \c isValueType. The \c importStatement,
34 \c inherits, \c inheritedBy, and \c nativeType fields are omitted when
35 they don't have values. Templates should use \c{existsIn()} to guard
36 access to optional fields.
37*/
39{
40 QJsonObject json;
41
42 if (!importStatement.isEmpty())
43 json["importStatement"_L1] = importStatement;
44 json["isSingleton"_L1] = isSingleton;
45 json["isValueType"_L1] = isValueType;
46
47 if (inherits) {
48 QJsonObject obj;
49 obj["name"_L1] = inherits->name;
50 obj["href"_L1] = inherits->href;
51 obj["moduleName"_L1] = inherits->moduleName;
52 json["inherits"_L1] = obj;
53 }
54
55 if (!inheritedBy.isEmpty()) {
56 QJsonArray arr;
57 for (const auto &entry : inheritedBy) {
58 QJsonObject obj;
59 obj["name"_L1] = entry.name;
60 obj["href"_L1] = entry.href;
61 arr.append(obj);
62 }
63 json["inheritedBy"_L1] = arr;
64 }
65
66 if (nativeType) {
67 QJsonObject obj;
68 obj["name"_L1] = nativeType->name;
69 obj["href"_L1] = nativeType->href;
70 json["nativeType"_L1] = obj;
71 }
72
73 return json;
74}
75
76static QJsonArray memberEntriesToJson(const QList<CollectionInfo::MemberEntry> &entries)
77{
78 QJsonArray arr;
79 for (const auto &entry : entries) {
80 QJsonObject obj;
81 obj["name"_L1] = entry.name;
82 obj["href"_L1] = entry.href;
83 obj["brief"_L1] = entry.brief;
84 arr.append(obj);
85 }
86 return arr;
87}
88
89/*!
90 Converts the CollectionInfo to a QJsonObject for template rendering.
91
92 Type flags (\c isModule, \c isQmlModule, \c isGroup) and \c noAutoList are
93 always emitted so templates can use unconditional checks. CMake/qmake build
94 variables are always emitted as empty strings when absent, for template
95 safety. Module metadata (\c logicalModuleName, \c logicalModuleVersion,
96 \c state) is conditionally emitted when non-empty. Member arrays are always
97 emitted (empty arrays when no entries) so Inja can iterate without guards.
98*/
100{
101 QJsonObject json;
102
103 json["isModule"_L1] = isModule;
104 json["isQmlModule"_L1] = isQmlModule;
105 json["isGroup"_L1] = isGroup;
106 json["noAutoList"_L1] = noAutoList;
107
108 if (!logicalModuleName.isEmpty())
109 json["logicalModuleName"_L1] = logicalModuleName;
110 if (!logicalModuleVersion.isEmpty())
111 json["logicalModuleVersion"_L1] = logicalModuleVersion;
112 if (!state.isEmpty())
113 json["state"_L1] = state;
114
115 if (!qtVariable.isEmpty())
116 json["qtVariable"_L1] = qtVariable;
117 if (!cmakePackage.isEmpty())
118 json["cmakePackage"_L1] = cmakePackage;
119 if (!cmakeComponent.isEmpty())
120 json["cmakeComponent"_L1] = cmakeComponent;
121 if (!cmakeTargetItem.isEmpty())
122 json["cmakeTargetItem"_L1] = cmakeTargetItem;
123
124 json["namespaces"_L1] = memberEntriesToJson(namespaces);
125 json["classes"_L1] = memberEntriesToJson(classes);
126 json["members"_L1] = memberEntriesToJson(members);
127
128 return json;
129}
130
131/*!
132 Converts CppReferenceInfo to a QJsonObject for template rendering.
133
134 Boolean flags and list fields are always emitted so templates can
135 iterate without guards. String fields are omitted when empty.
136 The access specifier on base class entries uses the {id, label}
137 convention from classificationjson.h.
138*/
140{
141 QJsonObject json;
142
143 if (!headerInclude.isEmpty())
144 json["headerInclude"_L1] = headerInclude;
145 if (!cmakeFindPackage.isEmpty())
146 json["cmakeFindPackage"_L1] = cmakeFindPackage;
147 if (!cmakeTargetLinkLibraries.isEmpty())
148 json["cmakeTargetLinkLibraries"_L1] = cmakeTargetLinkLibraries;
149 if (!qmakeVariable.isEmpty())
150 json["qmakeVariable"_L1] = qmakeVariable;
151 if (!statusText.isEmpty())
152 json["statusText"_L1] = statusText;
153 if (!statusCssClass.isEmpty())
154 json["statusCssClass"_L1] = statusCssClass;
155
156 if (qmlNativeType) {
157 QJsonObject obj;
158 obj["name"_L1] = qmlNativeType->name;
159 obj["href"_L1] = qmlNativeType->href;
160 json["qmlNativeType"_L1] = obj;
161 }
162
163 QJsonArray baseClassesArr;
164 for (const auto &entry : baseClasses) {
165 QJsonObject obj;
166 obj["name"_L1] = entry.name;
167 obj["href"_L1] = entry.href;
168 obj["access"_L1] = accessToJson(entry.access);
169 baseClassesArr.append(obj);
170 }
171 json["baseClasses"_L1] = baseClassesArr;
172
173 QJsonArray derivedClassesArr;
174 for (const auto &entry : derivedClasses) {
175 QJsonObject obj;
176 obj["name"_L1] = entry.name;
177 obj["href"_L1] = entry.href;
178 derivedClassesArr.append(obj);
179 }
180 json["derivedClasses"_L1] = derivedClassesArr;
181
182 json["suppressInheritance"_L1] = suppressInheritance;
183
184 QJsonArray templateDeclArr;
185 for (const auto &span : templateDeclSpans)
186 templateDeclArr.append(span.toJson());
187 json["templateDeclSpans"_L1] = templateDeclArr;
188
189 json["isInnerClass"_L1] = isInnerClass;
190 json["isNamespace"_L1] = isNamespace;
191 json["isHeader"_L1] = isHeader;
192
193 json["isPartialNamespace"_L1] = isPartialNamespace;
194 if (!fullNamespaceHref.isEmpty())
195 json["fullNamespaceHref"_L1] = fullNamespaceHref;
196 if (!fullNamespaceModuleName.isEmpty())
197 json["fullNamespaceModuleName"_L1] = fullNamespaceModuleName;
198
199 json["typeWord"_L1] = typeWord;
200
201 QJsonArray ancestorNamesArr;
202 for (const auto &name : ancestorNames)
203 ancestorNamesArr.append(name);
204 json["ancestorNames"_L1] = ancestorNamesArr;
205
206 if (!selfComparisonCategory.isEmpty())
207 json["selfComparisonCategory"_L1] = selfComparisonCategory;
208
209 QJsonArray comparisonArr;
210 for (const auto &entry : comparisonEntries) {
211 QJsonObject obj;
212 obj["category"_L1] = entry.category;
213 QJsonArray typesArr;
214 for (const auto &t : entry.comparableTypes)
215 typesArr.append(t);
216 obj["comparableTypes"_L1] = typesArr;
217 obj["description"_L1] = entry.description;
218 comparisonArr.append(obj);
219 }
220 json["comparisonEntries"_L1] = comparisonArr;
221
222 if (threadSafety) {
223 QJsonObject tsObj;
224 tsObj["level"_L1] = threadSafety->level;
225
226 auto exceptionListToJson = [](const QList<ThreadSafetyExceptionEntry> &entries) {
227 QJsonArray arr;
228 for (const auto &entry : entries) {
229 QJsonObject obj;
230 obj["name"_L1] = entry.name;
231 obj["href"_L1] = entry.href;
232 arr.append(obj);
233 }
234 return arr;
235 };
236
237 tsObj["reentrantExceptions"_L1] = exceptionListToJson(threadSafety->reentrantExceptions);
238 tsObj["threadSafeExceptions"_L1] = exceptionListToJson(threadSafety->threadSafeExceptions);
239 tsObj["nonReentrantExceptions"_L1] = exceptionListToJson(threadSafety->nonReentrantExceptions);
240 json["threadSafety"_L1] = tsObj;
241 }
242
243 if (!threadSafetyAdmonition.isEmpty()) {
244 QJsonArray admonitionArr;
245 for (const auto &block : threadSafetyAdmonition)
246 admonitionArr.append(block.toJson());
247 json["threadSafetyAdmonition"_L1] = admonitionArr;
248 }
249
250 QJsonArray groupsArr;
251 for (const auto &entry : groups) {
252 QJsonObject obj;
253 obj["name"_L1] = entry.name;
254 obj["href"_L1] = entry.href;
255 groupsArr.append(obj);
256 }
257 json["groups"_L1] = groupsArr;
258
259 json["hasObsoleteMembers"_L1] = hasObsoleteMembers;
260 if (!obsoleteMembersUrl.isEmpty())
261 json["obsoleteMembersUrl"_L1] = obsoleteMembersUrl;
262
263 return json;
264}
265
267{
268 switch (state) {
269 case NavigationInfo::CrumbState::Link:
270 return u"link"_s;
271 case NavigationInfo::CrumbState::Current:
272 return u"current"_s;
273 case NavigationInfo::CrumbState::Unresolved:
274 return u"unresolved"_s;
275 }
276 Q_UNREACHABLE_RETURN(u"link"_s);
277}
278
279/*!
280 Converts NavigationInfo to a QJsonObject for template rendering.
281
282 The \c breadcrumbs and \c tocEntries arrays are always emitted (empty
283 when none exist) so templates can iterate without guards. Each breadcrumb
284 carries a \c state discriminator (\c link, \c current, or \c unresolved)
285 so templates can distinguish a resolvable link, the current page, and
286 an unresolvable ancestor without conflating them through an empty href.
287 Sequential link objects (\c prevLink, \c nextLink, \c startLink) are
288 conditionally emitted only when set. The \c tocDepth integer is always
289 emitted (\c{-1} means unlimited depth).
290*/
292{
293 QJsonObject json;
294
295 QJsonArray breadcrumbArr;
296 for (const auto &entry : breadcrumbs) {
297 QJsonObject obj;
298 obj["title"_L1] = entry.title;
299 obj["href"_L1] = entry.href;
300 obj["state"_L1] = crumbStateString(entry.state);
301 breadcrumbArr.append(obj);
302 }
303 json["breadcrumbs"_L1] = breadcrumbArr;
304
305 if (previousLink) {
306 QJsonObject obj;
307 obj["title"_L1] = previousLink->title;
308 obj["href"_L1] = previousLink->href;
309 json["prevLink"_L1] = obj;
310 }
311
312 if (nextLink) {
313 QJsonObject obj;
314 obj["title"_L1] = nextLink->title;
315 obj["href"_L1] = nextLink->href;
316 json["nextLink"_L1] = obj;
317 }
318
319 if (startLink) {
320 QJsonObject obj;
321 obj["title"_L1] = startLink->title;
322 obj["href"_L1] = startLink->href;
323 json["startLink"_L1] = obj;
324 }
325
326 QJsonArray tocArr;
327 for (const auto &entry : tocEntries) {
328 QJsonObject obj;
329 obj["title"_L1] = entry.title;
330 obj["anchorId"_L1] = entry.anchorId;
331 obj["level"_L1] = entry.level;
332 tocArr.append(obj);
333 }
334 json["tocEntries"_L1] = tocArr;
335
336 json["tocDepth"_L1] = tocDepth;
337
338 return json;
339}
340
341/*!
342 Converts the Document to a QJsonObject for template rendering.
343
344 The JSON structure follows a convention where field names use camelCase
345 and match template variable names. Classification fields (nodeType, genus,
346 status, access) use a two-part structure with "id" (stable kebab-case
347 identifier for conditionals) and "label" (human-readable display name).
348
349 The \c contentJson field is nested under a 'content' key to provide better
350 structure and namespace separation in templates.
351
352 Returns a QJsonObject containing all IR data in a format suitable for
353 passing to the Inja template engine via InjaBridge.
354*/
355
357{
358 QJsonObject json;
359
360 // Classification (as {id, label} objects for template convenience)
361 // nodeType and genus are omitted when unclassified (NoType/DontCare),
362 // allowing templates to use `if defined` checks.
363 if (const auto t = nodeTypeToJson(nodeType))
364 json["nodeType"_L1] = *t;
365 if (const auto g = genusToJson(genus))
366 json["genus"_L1] = *g;
367 json["status"_L1] = statusToJson(status);
368 json["access"_L1] = accessToJson(access);
369
370 // Identity
371 json["title"_L1] = title;
372 json["fullTitle"_L1] = fullTitle;
373 json["url"_L1] = url;
374 if (!since.isEmpty())
375 json["since"_L1] = since;
376 if (!deprecatedSince.isEmpty())
377 json["deprecatedSince"_L1] = deprecatedSince;
378 if (!brief.isEmpty())
379 json["brief"_L1] = brief;
380
381 Q_ASSERT(!contentJson.contains("blocks"_L1));
382 QJsonObject content = contentJson;
383
384 QJsonArray blocks;
385 for (const auto &block : body)
386 blocks.append(block.toJson());
387 content["blocks"_L1] = blocks;
388
389 json["content"_L1] = content;
390
391 // QML type metadata (omitted for non-QML pages)
392 json["hasQmlType"_L1] = qmlTypeInfo.has_value();
393 if (qmlTypeInfo)
394 json["qmlType"_L1] = qmlTypeInfo->toJson();
395
396 // Collection metadata (module, QML module, and group pages).
397 json["hasCollection"_L1] = collectionInfo.has_value();
398 if (collectionInfo)
399 json["collection"_L1] = collectionInfo->toJson();
400
401 // C++ reference metadata (class, namespace, and header pages).
402 json["hasCppRef"_L1] = cppReferenceInfo.has_value();
403 if (cppReferenceInfo)
404 json["cppRef"_L1] = cppReferenceInfo->toJson();
405
406 // Navigation metadata (breadcrumbs, sequential links, TOC depth).
407 json["hasNavigation"_L1] = navigationInfo.has_value();
408 if (navigationInfo)
409 json["navigation"_L1] = navigationInfo->toJson();
410
411 // Members sub-page URL (always emitted for Inja root-level variable safety;
412 // empty string when no members sub-page was generated)
413 json["membersPageUrl"_L1] = membersPageUrl;
414
415 // Sections (for aggregate pages with member listings).
416 // Always emitted (even when empty) so templates can iterate safely
417 // without existsIn() guards on the root data object.
418 QJsonArray sectionsArray;
419 for (const auto &section : summarySections)
420 sectionsArray.append(section.toJson());
421 json["sections"_L1] = sectionsArray;
422
423 QJsonArray detailSectionsArray;
424 for (const auto &section : detailSections)
425 detailSectionsArray.append(section.toJson());
426 json["detailSections"_L1] = detailSectionsArray;
427
428 return json;
429}
430
431} // namespace IR
432
433QT_END_NAMESPACE
Definition builder.cpp:14
static QJsonArray memberEntriesToJson(const QList< CollectionInfo::MemberEntry > &entries)
Definition document.cpp:76
static QString crumbStateString(NavigationInfo::CrumbState state)
Definition document.cpp:266
Combined button and popup list for selecting options.
QJsonObject toJson() const
Converts the CollectionInfo to a QJsonObject for template rendering.
Definition document.cpp:99
QJsonObject toJson() const
Converts CppReferenceInfo to a QJsonObject for template rendering.
Definition document.cpp:139
Intermediate representation for a documentation topic.
Definition document.h:197
QJsonObject toJson() const
Converts the Document to a QJsonObject for template rendering.
Definition document.cpp:356
QJsonObject toJson() const
Converts NavigationInfo to a QJsonObject for template rendering.
Definition document.cpp:291
QJsonObject toJson() const
Converts the QmlTypeInfo to a QJsonObject for template rendering.
Definition document.cpp:38