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