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, \c isConcept) 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["isConcept"_L1] = isConcept;
107 json["noAutoList"_L1] = noAutoList;
108
109 if (!logicalModuleName.isEmpty())
110 json["logicalModuleName"_L1] = logicalModuleName;
111 if (!logicalModuleVersion.isEmpty())
112 json["logicalModuleVersion"_L1] = logicalModuleVersion;
113 if (!state.isEmpty())
114 json["state"_L1] = state;
115
116 if (!qtVariable.isEmpty())
117 json["qtVariable"_L1] = qtVariable;
118 if (!cmakePackage.isEmpty())
119 json["cmakePackage"_L1] = cmakePackage;
120 if (!cmakeComponent.isEmpty())
121 json["cmakeComponent"_L1] = cmakeComponent;
122 if (!cmakeTargetItem.isEmpty())
123 json["cmakeTargetItem"_L1] = cmakeTargetItem;
124
125 json["namespaces"_L1] = memberEntriesToJson(namespaces);
126 json["classes"_L1] = memberEntriesToJson(classes);
127 json["members"_L1] = memberEntriesToJson(members);
128
129 return json;
130}
131
132/*!
133 Converts CppReferenceInfo to a QJsonObject for template rendering.
134
135 Boolean flags and list fields are always emitted so templates can
136 iterate without guards. String fields are omitted when empty.
137 The access specifier on base class entries uses the {id, label}
138 convention from classificationjson.h.
139*/
141{
142 QJsonObject json;
143
144 if (!headerInclude.isEmpty())
145 json["headerInclude"_L1] = headerInclude;
146 if (!cmakeFindPackage.isEmpty())
147 json["cmakeFindPackage"_L1] = cmakeFindPackage;
148 if (!cmakeTargetLinkLibraries.isEmpty())
149 json["cmakeTargetLinkLibraries"_L1] = cmakeTargetLinkLibraries;
150 if (!qmakeVariable.isEmpty())
151 json["qmakeVariable"_L1] = qmakeVariable;
152 if (!statusText.isEmpty())
153 json["statusText"_L1] = statusText;
154 if (!statusCssClass.isEmpty())
155 json["statusCssClass"_L1] = statusCssClass;
156
157 if (qmlNativeType) {
158 QJsonObject obj;
159 obj["name"_L1] = qmlNativeType->name;
160 obj["href"_L1] = qmlNativeType->href;
161 json["qmlNativeType"_L1] = obj;
162 }
163
164 QJsonArray baseClassesArr;
165 for (const auto &entry : baseClasses) {
166 QJsonObject obj;
167 obj["name"_L1] = entry.name;
168 obj["href"_L1] = entry.href;
169 obj["access"_L1] = accessToJson(entry.access);
170 baseClassesArr.append(obj);
171 }
172 json["baseClasses"_L1] = baseClassesArr;
173
174 QJsonArray derivedClassesArr;
175 for (const auto &entry : derivedClasses) {
176 QJsonObject obj;
177 obj["name"_L1] = entry.name;
178 obj["href"_L1] = entry.href;
179 derivedClassesArr.append(obj);
180 }
181 json["derivedClasses"_L1] = derivedClassesArr;
182
183 json["suppressInheritance"_L1] = suppressInheritance;
184
185 QJsonArray templateDeclArr;
186 for (const auto &span : templateDeclSpans)
187 templateDeclArr.append(span.toJson());
188 json["templateDeclSpans"_L1] = templateDeclArr;
189
190 QJsonArray refConceptsArr;
191 for (const QString &name : referencedConcepts)
192 refConceptsArr.append(name);
193 json["referencedConcepts"_L1] = refConceptsArr;
194
195 json["isInnerClass"_L1] = isInnerClass;
196 json["isNamespace"_L1] = isNamespace;
197 json["isHeader"_L1] = isHeader;
198
199 json["isPartialNamespace"_L1] = isPartialNamespace;
200 if (!fullNamespaceHref.isEmpty())
201 json["fullNamespaceHref"_L1] = fullNamespaceHref;
202 if (!fullNamespaceModuleName.isEmpty())
203 json["fullNamespaceModuleName"_L1] = fullNamespaceModuleName;
204
205 json["typeWord"_L1] = typeWord;
206
207 QJsonArray ancestorNamesArr;
208 for (const auto &name : ancestorNames)
209 ancestorNamesArr.append(name);
210 json["ancestorNames"_L1] = ancestorNamesArr;
211
212 if (!selfComparisonCategory.isEmpty())
213 json["selfComparisonCategory"_L1] = selfComparisonCategory;
214
215 QJsonArray comparisonArr;
216 for (const auto &entry : comparisonEntries) {
217 QJsonObject obj;
218 obj["category"_L1] = entry.category;
219 QJsonArray typesArr;
220 for (const auto &t : entry.comparableTypes)
221 typesArr.append(t);
222 obj["comparableTypes"_L1] = typesArr;
223 obj["description"_L1] = entry.description;
224 comparisonArr.append(obj);
225 }
226 json["comparisonEntries"_L1] = comparisonArr;
227
228 if (threadSafety) {
229 QJsonObject tsObj;
230 tsObj["level"_L1] = threadSafety->level;
231
232 auto exceptionListToJson = [](const QList<ThreadSafetyExceptionEntry> &entries) {
233 QJsonArray arr;
234 for (const auto &entry : entries) {
235 QJsonObject obj;
236 obj["name"_L1] = entry.name;
237 obj["href"_L1] = entry.href;
238 arr.append(obj);
239 }
240 return arr;
241 };
242
243 tsObj["reentrantExceptions"_L1] = exceptionListToJson(threadSafety->reentrantExceptions);
244 tsObj["threadSafeExceptions"_L1] = exceptionListToJson(threadSafety->threadSafeExceptions);
245 tsObj["nonReentrantExceptions"_L1] = exceptionListToJson(threadSafety->nonReentrantExceptions);
246 json["threadSafety"_L1] = tsObj;
247 }
248
249 if (!threadSafetyAdmonition.isEmpty()) {
250 QJsonArray admonitionArr;
251 for (const auto &block : threadSafetyAdmonition)
252 admonitionArr.append(block.toJson());
253 json["threadSafetyAdmonition"_L1] = admonitionArr;
254 }
255
256 QJsonArray groupsArr;
257 for (const auto &entry : groups) {
258 QJsonObject obj;
259 obj["name"_L1] = entry.name;
260 obj["href"_L1] = entry.href;
261 groupsArr.append(obj);
262 }
263 json["groups"_L1] = groupsArr;
264
265 json["hasObsoleteMembers"_L1] = hasObsoleteMembers;
266 if (!obsoleteMembersUrl.isEmpty())
267 json["obsoleteMembersUrl"_L1] = obsoleteMembersUrl;
268
269 return json;
270}
271
273{
274 switch (state) {
275 case NavigationInfo::CrumbState::Link:
276 return u"link"_s;
277 case NavigationInfo::CrumbState::Current:
278 return u"current"_s;
279 case NavigationInfo::CrumbState::Unresolved:
280 return u"unresolved"_s;
281 }
282 Q_UNREACHABLE_RETURN(u"link"_s);
283}
284
285/*!
286 Converts NavigationInfo to a QJsonObject for template rendering.
287
288 The \c breadcrumbs and \c tocEntries arrays are always emitted (empty
289 when none exist) so templates can iterate without guards. Each breadcrumb
290 carries a \c state discriminator (\c link, \c current, or \c unresolved)
291 so templates can distinguish a resolvable link, the current page, and
292 an unresolvable ancestor without conflating them through an empty href.
293 Sequential link objects (\c prevLink, \c nextLink, \c startLink) are
294 conditionally emitted only when set. The \c tocDepth integer is always
295 emitted (\c{-1} means unlimited depth).
296*/
298{
299 QJsonObject json;
300
301 QJsonArray breadcrumbArr;
302 for (const auto &entry : breadcrumbs) {
303 QJsonObject obj;
304 obj["title"_L1] = entry.title;
305 obj["href"_L1] = entry.href;
306 obj["state"_L1] = crumbStateString(entry.state);
307 breadcrumbArr.append(obj);
308 }
309 json["breadcrumbs"_L1] = breadcrumbArr;
310
311 if (previousLink) {
312 QJsonObject obj;
313 obj["title"_L1] = previousLink->title;
314 obj["href"_L1] = previousLink->href;
315 json["prevLink"_L1] = obj;
316 }
317
318 if (nextLink) {
319 QJsonObject obj;
320 obj["title"_L1] = nextLink->title;
321 obj["href"_L1] = nextLink->href;
322 json["nextLink"_L1] = obj;
323 }
324
325 if (startLink) {
326 QJsonObject obj;
327 obj["title"_L1] = startLink->title;
328 obj["href"_L1] = startLink->href;
329 json["startLink"_L1] = obj;
330 }
331
332 QJsonArray tocArr;
333 for (const auto &entry : tocEntries) {
334 QJsonObject obj;
335 obj["title"_L1] = entry.title;
336 obj["anchorId"_L1] = entry.anchorId;
337 obj["level"_L1] = entry.level;
338 tocArr.append(obj);
339 }
340 json["tocEntries"_L1] = tocArr;
341
342 json["tocDepth"_L1] = tocDepth;
343
344 return json;
345}
346
347/*!
348 Converts the Document to a QJsonObject for template rendering.
349
350 The JSON structure follows a convention where field names use camelCase
351 and match template variable names. Classification fields (nodeType, genus,
352 status, access) use a two-part structure with "id" (stable kebab-case
353 identifier for conditionals) and "label" (human-readable display name).
354
355 The \c contentJson field is nested under a 'content' key to provide better
356 structure and namespace separation in templates.
357
358 Returns a QJsonObject containing all IR data in a format suitable for
359 passing to the Inja template engine via InjaBridge.
360*/
361
363{
364 QJsonObject json;
365
366 // Classification (as {id, label} objects for template convenience)
367 // nodeType and genus are omitted when unclassified (NoType/DontCare),
368 // allowing templates to use `if defined` checks.
369 if (const auto t = nodeTypeToJson(nodeType))
370 json["nodeType"_L1] = *t;
371 if (const auto g = genusToJson(genus))
372 json["genus"_L1] = *g;
373 json["status"_L1] = statusToJson(status);
374 json["access"_L1] = accessToJson(access);
375
376 // Identity
377 json["title"_L1] = title;
378 json["fullTitle"_L1] = fullTitle;
379 json["url"_L1] = url;
380 if (!since.isEmpty())
381 json["since"_L1] = since;
382 if (!deprecatedSince.isEmpty())
383 json["deprecatedSince"_L1] = deprecatedSince;
384 if (!brief.isEmpty())
385 json["brief"_L1] = brief;
386
387 Q_ASSERT(!contentJson.contains("blocks"_L1));
388 QJsonObject content = contentJson;
389
390 QJsonArray blocks;
391 for (const auto &block : body)
392 blocks.append(block.toJson());
393 content["blocks"_L1] = blocks;
394
395 json["content"_L1] = content;
396
397 // QML type metadata (omitted for non-QML pages)
398 json["hasQmlType"_L1] = qmlTypeInfo.has_value();
399 if (qmlTypeInfo)
400 json["qmlType"_L1] = qmlTypeInfo->toJson();
401
402 // Collection metadata (module, QML module, and group pages).
403 json["hasCollection"_L1] = collectionInfo.has_value();
404 if (collectionInfo)
405 json["collection"_L1] = collectionInfo->toJson();
406
407 // C++ reference metadata (class, namespace, and header pages).
408 json["hasCppRef"_L1] = cppReferenceInfo.has_value();
409 if (cppReferenceInfo)
410 json["cppRef"_L1] = cppReferenceInfo->toJson();
411
412 // Navigation metadata (breadcrumbs, sequential links, TOC depth).
413 json["hasNavigation"_L1] = navigationInfo.has_value();
414 if (navigationInfo)
415 json["navigation"_L1] = navigationInfo->toJson();
416
417 // Members sub-page URL (always emitted for Inja root-level variable safety;
418 // empty string when no members sub-page was generated)
419 json["membersPageUrl"_L1] = membersPageUrl;
420
421 // Sections (for aggregate pages with member listings).
422 // Always emitted (even when empty) so templates can iterate safely
423 // without existsIn() guards on the root data object.
424 QJsonArray sectionsArray;
425 for (const auto &section : summarySections)
426 sectionsArray.append(section.toJson());
427 json["sections"_L1] = sectionsArray;
428
429 QJsonArray detailSectionsArray;
430 for (const auto &section : detailSections)
431 detailSectionsArray.append(section.toJson());
432 json["detailSections"_L1] = detailSectionsArray;
433
434 return json;
435}
436
437} // namespace IR
438
439QT_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:272
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:140
Intermediate representation for a documentation topic.
Definition document.h:199
QJsonObject toJson() const
Converts the Document to a QJsonObject for template rendering.
Definition document.cpp:362
QJsonObject toJson() const
Converts NavigationInfo to a QJsonObject for template rendering.
Definition document.cpp:297
QJsonObject toJson() const
Converts the QmlTypeInfo to a QJsonObject for template rendering.
Definition document.cpp:38